首页 文章

SceneKit - 将立方体纹理映射到框

提问于
浏览
4

我有一个看起来像立方体的纹理

在此输入图像描述

我想在 SceneKit 视图中的立方体上使用它。我正在使用 SceneKit 几何SCNBox。不幸的是,结果是纹理完全投射在每个面上,而不是仅使用相应的部分:

let videoGeometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
videoGeometry.firstMaterial?.isDoubleSided = true
videoGeometry.firstMaterial?.diffuse.contents = UIImage(named: "test")!

我知道我可以在几何体上使用着色器修改器,但我不知道从哪里开始。由于纹理目前使用了六次,我的直觉是SCNBox几何可能不适合我的目标,但我真的不知道如何改变它。

1 回答

  • 7

    您可以使用自定义几何体来创建它:创建一个立方体(http://ronnqvi.st/custom-scenekit-geometry/是一个开始的好地方),您可以在顶部添加一些自定义纹理映射。让索引正确(对我而言)有点棘手,但最后它运行良好:

    func getSimpleCubeGeo() -> SCNGeometry {
        let halfSide = Float(0.5)
    
        /* The cube vertex are like:
    
            5---------4
           /.        /|
          / .       / |
         7---------6  |
         |  .      |  |
         |  .      |  |
         |  1......|..0
         | .       | /
         |.        |/
         3---------2
    
         */
        let _positions = [
            SCNVector3(x:-halfSide, y:-halfSide, z:  halfSide),
            SCNVector3(x: halfSide, y:-halfSide, z:  halfSide),
            SCNVector3(x:-halfSide, y:-halfSide, z: -halfSide),
            SCNVector3(x: halfSide, y:-halfSide, z: -halfSide),
            SCNVector3(x:-halfSide, y: halfSide, z:  halfSide),
            SCNVector3(x: halfSide, y: halfSide, z:  halfSide),
            SCNVector3(x:-halfSide, y: halfSide, z: -halfSide),
            SCNVector3(x: halfSide, y: halfSide, z: -halfSide),
        ]
    
        // points are tripled since they are each used on 3 faces
        // and there's no continuity in the UV mapping
        // so we need to duplicate the points
        //
        // we'll use the first third for the faces orthogonal to the X (left) axis,
        // the second for the Y (top) axis and the third for the Z (front) axis
        let positions = _positions + _positions + _positions
    
        let X = 0
        let Y = 8
        let Z = 16
    
        let indices = [
            // bottom
            0 + Y, 2 + Y, 1 + Y,
            1 + Y, 2 + Y, 3 + Y,
            // back
            2 + Z, 6 + Z, 3 + Z,
            3 + Z, 6 + Z, 7 + Z,
            // left
            0 + X, 4 + X, 2 + X,
            2 + X, 4 + X, 6 + X,
            // right
            1 + X, 3 + X, 5 + X,
            3 + X, 7 + X, 5 + X,
            // front
            0 + Z, 1 + Z, 4 + Z,
            1 + Z, 5 + Z, 4 + Z,
            // top
            4 + Y, 5 + Y, 6 + Y,
            5 + Y, 7 + Y, 6 + Y,
        ]
    
        // get the points in the texture where the faces are split
        var textureSplitPoints = [CGPoint]()
        for i in 0...12 {
            let x = Double(i % 4)
            let y = Double(i / 4)
            textureSplitPoints.append(CGPoint(x: x / 3.0, y: y / 2.0))
        }
        let textCoords = [
            textureSplitPoints[4],
            textureSplitPoints[6],
            textureSplitPoints[5],
            textureSplitPoints[5],
            textureSplitPoints[8],
            textureSplitPoints[10],
            textureSplitPoints[9],
            textureSplitPoints[9],
    
            textureSplitPoints[5],
            textureSplitPoints[4],
            textureSplitPoints[1],
            textureSplitPoints[0],
            textureSplitPoints[7],
            textureSplitPoints[6],
            textureSplitPoints[11],
            textureSplitPoints[10],
    
            textureSplitPoints[2],
            textureSplitPoints[1],
            textureSplitPoints[2],
            textureSplitPoints[3],
            textureSplitPoints[6],
            textureSplitPoints[5],
            textureSplitPoints[6],
            textureSplitPoints[7],
        ]
    
        let vertexSource = SCNGeometrySource(vertices: positions)
    
        let textSource = SCNGeometrySource(textureCoordinates: textCoords)
        let indexData = NSData(bytes: indices, length: sizeof(Int) * indices.count)
        let elements = SCNGeometryElement(
            data: indexData as Data,
            primitiveType: SCNGeometryPrimitiveType.triangles,
            primitiveCount: indices.count / 3,
            bytesPerIndex: sizeof(Int)
        )
        return SCNGeometry(sources: [vertexSource, textSource], elements: [elements])
    }
    

相关问题