Creating a custom SCNGeometry polygon plane with SCNGeometryPrimitiveType polygon crash/error

僤鯓⒐⒋嵵緔 提交于 2019-12-03 08:31:42

SOLUTION (Copy-paste this macOS app code for testing in ViewController.swift):

import SceneKit

class ViewController: NSViewController, SCNSceneRendererDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let scene = SCNScene()
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.camera?.zFar = 1000
        scene.rootNode.addChildNode(cameraNode)
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

        let scnView = self.view as! SCNView
        scnView.scene = scene
        scnView.delegate = self
        scnView.allowsCameraControl = true
        scnView.showsStatistics = true
        scnView.backgroundColor = NSColor.darkGray

        func model( v01: SCNVector3,
                    v02: SCNVector3,
                    v03: SCNVector3,
                    v04: SCNVector3,
                    v05: SCNVector3,
                    v06: SCNVector3,
                    v07: SCNVector3,
                    v08: SCNVector3,
                    v09: SCNVector3,
                    v10: SCNVector3,
                    v11: SCNVector3,
                    v12: SCNVector3,
                    v13: SCNVector3,
                    v14: SCNVector3,
                    v15: SCNVector3,
                    v16: SCNVector3,
                    v17: SCNVector3,
                    v18: SCNVector3) -> SCNNode {

            let polyDraw = draw(vector01: v01,
                                vector02: v02,
                                vector03: v03,
                                vector04: v04,
                                vector05: v05,
                                vector06: v06,
                                vector07: v07,
                                vector08: v08,
                                vector09: v09,
                                vector10: v10,
                                vector11: v11,
                                vector12: v12,
                                vector13: v13,
                                vector14: v14,
                                vector15: v15,
                                vector16: v16,
                                vector17: v17,
                                vector18: v18)

            let material = SCNMaterial()
            material.diffuse.contents = NSColor.green
            material.isDoubleSided = true
            polyDraw.materials = [material]

            let node = SCNNode(geometry: polyDraw)
            node.scale =  SCNVector3(x: 200, y: 200, z: 200)
            scene.rootNode.addChildNode(node)
            return node
        }

        func draw(vector01: SCNVector3,
                  vector02: SCNVector3,
                  vector03: SCNVector3,
                  vector04: SCNVector3,
                  vector05: SCNVector3,
                  vector06: SCNVector3,
                  vector07: SCNVector3,
                  vector08: SCNVector3,
                  vector09: SCNVector3,
                  vector10: SCNVector3,
                  vector11: SCNVector3,
                  vector12: SCNVector3,
                  vector13: SCNVector3,
                  vector14: SCNVector3,
                  vector15: SCNVector3,
                  vector16: SCNVector3,
                  vector17: SCNVector3,
                  vector18: SCNVector3) -> SCNGeometry {

            let normalsPerFace = 1

            let indices: [Int32] = [18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                                        10, 11, 12, 13, 14, 15, 16, 17]

            let source = SCNGeometrySource(vertices: [vector01,
                                                      vector02,
                                                      vector03,
                                                      vector04,
                                                      vector05,
                                                      vector06,
                                                      vector07,
                                                      vector08,
                                                      vector09,
                                                      vector10,
                                                      vector11,
                                                      vector12,
                                                      vector13,
                                                      vector14,
                                                      vector15,
                                                      vector16,
                                                      vector17,
                                                      vector18])

            let vec = [vector01, vector02, vector03,
                       vector04, vector05, vector06,
                       vector07, vector08, vector09,
                       vector10, vector11, vector12,
                       vector13, vector14, vector15,
                       vector16, vector17, vector18].map { [SCNVector3](repeating: $0,
                                                                            count: normalsPerFace) }.flatMap{ $0 }
            let normals: [SCNVector3] = vec
            let normalSource = SCNGeometrySource(normals: normals)

            let point01 = CGPoint(x: CGFloat(vector01.x), y: CGFloat(vector01.y))
            let point02 = CGPoint(x: CGFloat(vector02.x), y: CGFloat(vector02.y))
            let point03 = CGPoint(x: CGFloat(vector03.x), y: CGFloat(vector03.y))
            let point04 = CGPoint(x: CGFloat(vector04.x), y: CGFloat(vector04.y))
            let point05 = CGPoint(x: CGFloat(vector05.x), y: CGFloat(vector05.y))
            let point06 = CGPoint(x: CGFloat(vector06.x), y: CGFloat(vector06.y))
            let point07 = CGPoint(x: CGFloat(vector07.x), y: CGFloat(vector07.y))
            let point08 = CGPoint(x: CGFloat(vector08.x), y: CGFloat(vector08.y))
            let point09 = CGPoint(x: CGFloat(vector09.x), y: CGFloat(vector09.y))
            let point10 = CGPoint(x: CGFloat(vector10.x), y: CGFloat(vector10.y))
            let point11 = CGPoint(x: CGFloat(vector11.x), y: CGFloat(vector11.y))
            let point12 = CGPoint(x: CGFloat(vector12.x), y: CGFloat(vector12.y))
            let point13 = CGPoint(x: CGFloat(vector13.x), y: CGFloat(vector13.y))
            let point14 = CGPoint(x: CGFloat(vector14.x), y: CGFloat(vector14.y))
            let point15 = CGPoint(x: CGFloat(vector15.x), y: CGFloat(vector15.y))
            let point16 = CGPoint(x: CGFloat(vector16.x), y: CGFloat(vector16.y))
            let point17 = CGPoint(x: CGFloat(vector17.x), y: CGFloat(vector17.y))
            let point18 = CGPoint(x: CGFloat(vector18.x), y: CGFloat(vector18.y))

            let texCoord = SCNGeometrySource(textureCoordinates:
                           [point01, point02, point03, point04, point05, point06,
                            point07, point08, point09, point10, point11, point12,
                            point13, point14, point15, point16, point17, point18])

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

            let element = SCNGeometryElement(data: data,
                                    primitiveType: .polygon,
                                   primitiveCount: 1,
                                    bytesPerIndex: MemoryLayout<Int32>.size)

            let geometry = SCNGeometry(sources: [source, normalSource, texCoord],
                                      elements: [element])

            return geometry
        }

        _ = model(v01: SCNVector3(x: 0.08866002, y: -0.00773552, z: -0.09841499),
                  v02: SCNVector3(x: 0.08873053, y: -0.01492687, z: -0.09837532),
                  v03: SCNVector3(x: 0.08873053, y: -0.01492687, z: -0.09837532),
                  v04: SCNVector3(x: 0.08846086, y: -0.02434851, z: -0.09852711),
                  v05: SCNVector3(x: 0.08749959, y: -0.03475155, z: -0.09906833),
                  v06: SCNVector3(x: 0.08527064, y: -0.04331201, z: -0.10032329),
                  v07: SCNVector3(x: 0.08125973, y: -0.04962304, z: -0.10258152),
                  v08: SCNVector3(x: 0.07674095, y: -0.05456349, z: -0.10512567),
                  v09: SCNVector3(x: 0.07041831, y: -0.05790819, z: -0.10868551),
                  v10: SCNVector3(x: 0.06373097, y: -0.05820452, z: -0.11245064),
                  v11: SCNVector3(x: 0.05844573, y: -0.05779012, z: -0.11542635),
                  v12: SCNVector3(x: 0.05448552, y: -0.05334358, z: -0.11765605),
                  v13: SCNVector3(x: 0.05290238, y: -0.04610482, z: -0.11854740),
                  v14: SCNVector3(x: 0.05353430, y: -0.03637475, z: -0.11819161),
                  v15: SCNVector3(x: 0.05589097, y: -0.02788102, z: -0.11686475),
                  v16: SCNVector3(x: 0.05910149, y: -0.02275178, z: -0.11505718),
                  v17: SCNVector3(x: 0.06234538, y: -0.02150976, z: -0.11323079),
                  v18: SCNVector3(x: 0.06506948, y: -0.02217681, z: -0.11169703))
    }
}

USEFUL INFO:

In 3D graphics the best and most predictable way to work with polygonal geometry is to initially use three-sided (triangles) and four-sided (quadrangles) faces. Sometimes, in rare cases, you can use five-sided faces but this can lead you to shading artefacts.

Bad cases that can potentially lead to errors in SceneKit/Metal are:

  • Lamina Faces
  • Non-Manifold Geometry
  • Non-planar Faces (your case)
  • Concave Faces
  • "Turned inside out" Faces i.e. wrong connection's order (your case)
  • Faces with Holes
  • Faces with Edges that have a zero length
  • etc...

And one more important thing I should say is: at rendering stage all polygons always turn into triangles. If renderer or rendering engine can't fulfil this transformation you'll get errors.

Look how four-sided polygons are competently connected to form a complex object:

P.S. camera.zFar for ARKit.

let currentFrame = sceneView.session.currentFrame
let node = SCNNode()
node.camera = SCNCamera()

var translation = matrix_identity_float4x4

translation.columns.3.z = -0.1       /* 10 cm */
node.simdTransform = matrix_multiply((currentFrame?.camera.transform)!, 
                                      translation)

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