SceneKit - Map cube texture to box

旧城冷巷雨未停 提交于 2020-01-02 05:46:04

问题


I've a texture for a cube that looks like

I'd like to use it on a cube in a SceneKit view. I'm using the SceneKit geometry SCNBox for that. Unfortunately, the result is that the texture is projected entirely on each face, instead of using only the corresponding part:

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

I know I can use shader modifiers on the geometry but I'm not sure where to get started. Since the texture is currently used six times, my intuition is that the SCNBox geometry might not be adapted to my goal, but I don't really know how to change it.


回答1:


You can get it to work with a custom geometry: create a cube (http://ronnqvi.st/custom-scenekit-geometry/ is a good place to get started) and you can add some custom texture mapping on top. It's a bit tricky to get the indices right (was for me), but at the end it worked fine:

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])
}


来源:https://stackoverflow.com/questions/38949083/scenekit-map-cube-texture-to-box

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!