Home > Software engineering >  How to create a SCNNode with a custom geometry?
How to create a SCNNode with a custom geometry?

Time:01-21

I am trying to create a SCNNode whose geometry is created using an array of x, y, and z positions. I am using the following code; however, this is not showing up. Does anyone know what's wrong?

class CustomShapeNode: SCNNode {
    init(positions: [(Double, Double, Double)]) {
        super.init()
        
        // Create an array of SCNVector3 from the positions array
        var scnPositions = [SCNVector3]()
        for position in positions {
            scnPositions.append(SCNVector3(Float(position.0), Float(position.1), Float(position.2)))
        }
        
        // Create a geometry from the positions array
        let geometry = SCNGeometry(sources: [SCNGeometrySource(vertices: scnPositions)], elements: [SCNGeometryElement(indices: Array(0..<scnPositions.count), primitiveType: .triangles)])
        
        // Set the geometry to the node
        self.geometry = geometry
        
        // Set the color of the node geometry
        self.geometry?.firstMaterial?.diffuse.contents = UIColor.red
    }

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

CodePudding user response:

Use the following code:

import SceneKit

class ViewController: UIViewController {

    var sceneView: SCNView? = nil
    
    let node = CustomShapeNode([SCNVector3( 0,0,0),       // CCW
                                SCNVector3( 1,1,0),
                                SCNVector3(-1,1,0)])

    override func viewDidLoad() {
        super.viewDidLoad()

        sceneView = self.view as? SCNView
        sceneView?.scene = SCNScene()
        sceneView?.backgroundColor = .darkGray
        sceneView?.allowsCameraControl = true
        sceneView?.scene?.rootNode.addChildNode(node)
    }
}

class CustomShapeNode: SCNNode {
        
    init(_ positions: [SCNVector3]) {
        super.init()
        
        let normalsPerFace = 1
        let indices: [Int32] = [0, 1, 2]

        let source = SCNGeometrySource(vertices: [positions[0],
                                                  positions[1],
                                                  positions[2]])

        let normals = [positions[0],positions[1],positions[2]].map {
            [SCNVector3](repeating: $0, count: normalsPerFace)
        }.flatMap { $0 }

        let normalSource = SCNGeometrySource(normals: normals)
        let data = Data(bytes: indices,
                        count: indices.count * MemoryLayout<Int32>.size)

        let element = SCNGeometryElement(data: data,
                                primitiveType: .triangles,
                               primitiveCount: 1,
                                bytesPerIndex: MemoryLayout<Int32>.size)
        
        let p1 = CGPoint(x: CGFloat(positions[0].x),
                         y: CGFloat(positions[0].y))
        let p2 = CGPoint(x: CGFloat(positions[1].x),
                         y: CGFloat(positions[1].y))
        let p3 = CGPoint(x: CGFloat(positions[2].x),
                         y: CGFloat(positions[2].y))
            
        let texCoord = SCNGeometrySource(textureCoordinates: [p1, p2, p3])
                    
        self.geometry = SCNGeometry(sources: [source, normalSource, texCoord],
                                   elements: [element])
                
        self.geometry?.firstMaterial?.diffuse.contents = UIColor.systemOrange
        self.geometry?.firstMaterial?.lightingModel = .constant
        self.geometry?.firstMaterial?.isDoubleSided = true
    }

    required init?(coder: NSCoder) {
        fatalError("Hasn't been implemented yet")
    }
}

enter image description here

  • Related