【问题标题】:SceneKit issues applying texture to custom geometrySceneKit 问题将纹理应用于自定义几何体
【发布时间】:2018-08-06 23:11:18
【问题描述】:

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

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

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

问候

【问题讨论】:

    标签: swift scenekit texture-mapping


    【解决方案1】:

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

    另一种看待它的方式是,您用于引用顶点的同一索引也用于引用纹理坐标,因此由于您只有 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
    };
    

    【讨论】:

    • 谢谢大卫,它似乎工作正常(我需要调整我的代码以获得我想要的面部纹理,但这个代码并不太难),但我有一个问题,为什么UV坐标的顺序这么乱?我只是不明白顺序,前 4 个是底部,4 个顶部,2 个前部,2 个后部,然后是 2 个前部,等等
    • 也看不出索引、法线和UV贴图的相关性在哪里,因为索引顺序是bottom、back、left、right、front和top,法线是top、bottom、back ,前,左和右,以及我在上一条评论中指出的 uv 映射。
    【解决方案2】:

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

    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)
    

    【讨论】:

    • 问题是我需要这是一个自定义几何体,我可以使用 SCN* 几何体,但我需要自定义它们,即风格化立方体(圆角)或坡道等
    • 那么我相信大卫是你最好的选择:)
    • 是的,我没有回复他的回答,因为我还没有时间听从他的建议,但似乎是这样。
    猜你喜欢
    • 2023-04-10
    • 1970-01-01
    • 2018-03-05
    • 2016-04-28
    • 2016-11-25
    • 2021-08-01
    • 1970-01-01
    • 2018-09-10
    • 2019-09-24
    相关资源
    最近更新 更多