SceneKit 问题将纹理应用于自定义几何体

SceneKit issues applying texture to custom geometry

我在将纹理应用于自定义几何体时遇到问题,这就是现在的结果

但我希望每张脸都有不同的纹理,而我的纹理是

This is the code that I've used to generate the cube,我尝试了很多方法,但对我没有任何作用,我知道我正在做的事情有问题,但我不明白。

此致

单个顶点不能有多个纹理坐标。由于立方体中的每个顶点都出现在一个角上并且是三个不同面的一部分,因此您需要重复顶点数据三次并将其与纹理坐标匹配,然后将它们与索引一起引用。

另一种看待它的方式是,您用来引用顶点的同一索引也用于引用纹理坐标,因此由于您只有 8 个顶点,因此您只能引用前 8 个纹理坐标。

在我关于 SceneKit 的书中的一章中 I create a custom cube geometry。它的纹理坐标显示每个面上的完整纹理——因此您必须更改该部分——但它的索引也应该适用于您的立方体:

// Indices that turn the source data into triangles
// ------------------------------------------------

int indices[] = {
    // bottom
    0, 2, 1,
    1, 2, 3,
    // back
    10, 14, 11,  // 2, 6, 3,   + 8
    11, 14, 15,  // 3, 6, 7,   + 8
    // left
    16, 20, 18,  // 0, 4, 2,   + 16
    18, 20, 22,  // 2, 4, 6,   + 16
    // right
    17, 19, 21,  // 1, 3, 5,   + 16
    19, 23, 21,  // 3, 7, 5,   + 16
    // front
    8,  9, 12,  // 0, 1, 4,   + 8
    9, 13, 12,  // 1, 5, 4,   + 8
    // top
    4, 5, 6,
    5, 7, 6
};

// Custom geometry data for a cube
// -------------------------------

SCNVector3 vertices[] = {
    SCNVector3Make(-halfSide, -halfSide,  halfSide),
    SCNVector3Make( halfSide, -halfSide,  halfSide),
    SCNVector3Make(-halfSide, -halfSide, -halfSide),
    SCNVector3Make( halfSide, -halfSide, -halfSide),
    SCNVector3Make(-halfSide,  halfSide,  halfSide),
    SCNVector3Make( halfSide,  halfSide,  halfSide),
    SCNVector3Make(-halfSide,  halfSide, -halfSide),
    SCNVector3Make( halfSide,  halfSide, -halfSide),

    // repeat exactly the same
    SCNVector3Make(-halfSide, -halfSide,  halfSide),
    SCNVector3Make( halfSide, -halfSide,  halfSide),
    SCNVector3Make(-halfSide, -halfSide, -halfSide),
    SCNVector3Make( halfSide, -halfSide, -halfSide),
    SCNVector3Make(-halfSide,  halfSide,  halfSide),
    SCNVector3Make( halfSide,  halfSide,  halfSide),
    SCNVector3Make(-halfSide,  halfSide, -halfSide),
    SCNVector3Make( halfSide,  halfSide, -halfSide),

    // repeat exactly the same
    SCNVector3Make(-halfSide, -halfSide,  halfSide),
    SCNVector3Make( halfSide, -halfSide,  halfSide),
    SCNVector3Make(-halfSide, -halfSide, -halfSide),
    SCNVector3Make( halfSide, -halfSide, -halfSide),
    SCNVector3Make(-halfSide,  halfSide,  halfSide),
    SCNVector3Make( halfSide,  halfSide,  halfSide),
    SCNVector3Make(-halfSide,  halfSide, -halfSide),
    SCNVector3Make( halfSide,  halfSide, -halfSide)
};

SCNVector3 normals[] = {
    // up and down
    SCNVector3Make( 0, -1, 0),
    SCNVector3Make( 0, -1, 0),
    SCNVector3Make( 0, -1, 0),
    SCNVector3Make( 0, -1, 0),

    SCNVector3Make( 0, 1, 0),
    SCNVector3Make( 0, 1, 0),
    SCNVector3Make( 0, 1, 0),
    SCNVector3Make( 0, 1, 0),

    // back and front
    SCNVector3Make( 0, 0,  1),
    SCNVector3Make( 0, 0,  1),
    SCNVector3Make( 0, 0, -1),
    SCNVector3Make( 0, 0, -1),

    SCNVector3Make( 0, 0, 1),
    SCNVector3Make( 0, 0, 1),
    SCNVector3Make( 0, 0, -1),
    SCNVector3Make( 0, 0, -1),

    // left and right
    SCNVector3Make(-1, 0, 0),
    SCNVector3Make( 1, 0, 0),
    SCNVector3Make(-1, 0, 0),
    SCNVector3Make( 1, 0, 0),

    SCNVector3Make(-1, 0, 0),
    SCNVector3Make( 1, 0, 0),
    SCNVector3Make(-1, 0, 0),
    SCNVector3Make( 1, 0, 0),
};

CGPoint UVs[] = {
    CGPointMake(0, 0), // bottom
    CGPointMake(1, 0), // bottom
    CGPointMake(0, 1), // bottom
    CGPointMake(1, 1), // bottom

    CGPointMake(0, 1), // top
    CGPointMake(1, 1), // top
    CGPointMake(0, 0), // top
    CGPointMake(1, 0), // top

    CGPointMake(0, 1), // front
    CGPointMake(1, 1), // front
    CGPointMake(1, 1), // back
    CGPointMake(0, 1), // back

    CGPointMake(0, 0), // front
    CGPointMake(1, 0), // front
    CGPointMake(1, 0), // back
    CGPointMake(0, 0), // back

    CGPointMake(1, 1), // left
    CGPointMake(0, 1), // right
    CGPointMake(0, 1), // left
    CGPointMake(1, 1), // right

    CGPointMake(1, 0), // left
    CGPointMake(0, 0), // right
    CGPointMake(0, 0), // left
    CGPointMake(1, 0), // right
};

虽然这是一种不同的方法,但我制作了一个 Box Class 可以正确渲染每一面:

class Box: SCNNode {

private var faceArray = [SCNMaterial]()

/// Creates An SCNBox With Either A Colour Or UIImage For Each Of It's Faces
/// (Either An Array [Colour] Or [UIImage] Must Be Input)
/// - Parameters:
///   - width: Optional CGFloat (Defaults To 20cm)
///   - height: Optional CGFloat (Defaults To 20cm)
///   - length: Optional CGFloat (Defaults To 20cm)
///   - colours: Optional [UIColor] - [Front, Right, Back, Left, Top, Bottom]
///   - images: Optional [UIImage] - [Front, Right, Back, Left, Top, Bottom]
init(width: CGFloat = 0.2, height: CGFloat = 0.2, length: CGFloat = 0.2, colours: [UIColor]?, images: [UIImage]?) {

    super.init()

    self.geometry = SCNBox(width: width, height: height, length: length, chamferRadius: 0)

    var sideArray = [Any]()

    if colours == nil{
        guard let imageArray = images else { return }
        sideArray = imageArray
    }else{
        guard let coloursArray = colours else { return }
        sideArray = coloursArray
    }

    for index in 0 ..< 6{
        let face = SCNMaterial()
        face.diffuse.contents = sideArray[index]
        faceArray.append(face)
    }

    self.geometry?.materials = faceArray

}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
   }

}

你可以像这样初始化它,通过旋转可以看到每个面都正确渲染:

    let cube = Box(colours: [.red, .green, .cyan, .yellow, .blue, .black], images: nil)
    scene.rootNode.addChildNode(cube)

    let rotateAction = SCNAction.rotate(by: .pi * 2, around: SCNVector3(1, 0, 0), duration: 10)

    cube.runAction(rotateAction)