jjzjj

swift - 使用 SCNGeometryPrimitiveType 多边形崩溃/错误创建自定义 SCNGeometry 多边形平面

coder 2023-09-07 原文

我正在尝试创建一个具有自定义形状的平面形式的自定义 SCNGeometry,它可以放置在 ARKit session 中。我在以下方法中使用选项 SCNGeometryPrimitiveTypePolygon 似乎工作正常:

extension SCNGeometry {

    static func polygonPlane(vertices: [SCNVector3]) -> SCNGeometry {

        var indices: [Int32] = [Int32(vertices.count)]

        var index: Int32 = 0
        for _ in vertices {
            indices.append(index)
            index += 1
        }
        let vertexSource = SCNGeometrySource(vertices: vertices)
        let indexData = Data(bytes: indices, count: indices.count * MemoryLayout<Int32>.size)
        let element = SCNGeometryElement(data: indexData, primitiveType: .polygon, primitiveCount: 1, bytesPerIndex: MemoryLayout<Int32>.size)
        let geometry = SCNGeometry(sources: [vertexSource], elements: [element])
        let material = SCNMaterial()
        material.diffuse.contents = UIColor.blue
        material.isDoubleSided = true
        geometry.firstMaterial = material
        return geometry
    }

创建此几何体后,我将其分配给 SCNNode:s .geometry 属性,并像往常一样将其添加到我的 AR 场景中:

let geometry = SCNGeometry.polygonPlane(vertices: verticesArray)
let node = SCNNode(geometry: geometry)
sceneView.scene.rootNode.addChildNode(node)

这适用于某些类型的平面形状。然而,我经常遇到崩溃,主要是在使用复杂的形状或许多顶点来勾勒平面形状时。我已经试验过了,看起来几何体是按预期创建的,没有任何错误,但是当节点被添加到场景中并即将被渲染时会发生错误。这是打印的错误:

-[MTLDebugDevice validateNewBufferArgs:options:]:467: failed assertion `Cannot create buffer of zero length.'

调试导航器中显示的内容:

最后是堆栈跟踪:

* thread #17, name = 'com.apple.scenekit.scnview-renderer', queue = 'com.apple.scenekit.renderingQueue.ARSCNView0x11be03ed0', stop reason = signal SIGABRT
  * frame #0: 0x0000000219cad0cc libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x0000000219d23a88 libsystem_pthread.dylib`pthread_kill + 300
    frame #2: 0x0000000219c0614c libsystem_c.dylib`abort + 144
    frame #3: 0x0000000219bd3274 libsystem_c.dylib`__assert_rtn + 224
    frame #4: 0x000000021c28e23c Metal`MTLReportFailure + 528
    frame #5: 0x000000023f984108 MetalTools`-[MTLDebugDevice validateNewBufferArgs:options:] + 172
    frame #6: 0x000000023f98430c MetalTools`-[MTLDebugDevice newBufferWithBytes:length:options:] + 128
    frame #7: 0x000000022e323b48 SceneKit`-[SCNMTLResourceManager _bufferForData:bytesPerIndex:] + 404
    frame #8: 0x000000022e323f14 SceneKit`-[SCNMTLResourceManager renderResourceForMeshElement:] + 416
    frame #9: 0x000000022e3243c0 SceneKit`-[SCNMTLResourceManager renderResourceForMesh:dataKind:] + 692
    frame #10: 0x000000022e364980 SceneKit`_execute(SCNMTLRenderContext*, DrawCommand) + 916
    frame #11: 0x000000022e3644a0 SceneKit`-[SCNMTLRenderContext drawRenderElement:withPass:] + 608
    frame #12: 0x000000022e3630d4 SceneKit`-[SCNMTLRenderContext processRendererElements:count:engineIterationContext:] + 1044
    frame #13: 0x000000022e4afc54 SceneKit`C3D::DrawNodesPass::_renderEye(long) + 472
    frame #14: 0x000000022e4afa00 SceneKit`C3D::DrawNodesPass::execute(C3D::RenderArgs const&) + 260
    frame #15: 0x000000022e54a1b4 SceneKit`C3D::MainPass::execute(C3D::RenderArgs const&) + 176
    frame #16: 0x000000022e318904 SceneKit`C3D::__renderSlice(C3D::RenderGraph*, C3D::RenderPass*, unsigned short&, C3D::RenderGraph::GraphNode const&, C3D::RenderGraph::Stage*&, C3D::RenderArgs) + 1156
    frame #17: 0x000000022e319cd0 SceneKit`C3D::RenderGraph::execute() + 3896
    frame #18: 0x000000022e42fd8c SceneKit`-[SCNRenderer _renderSceneWithEngineContext:sceneTime:] + 2364
    frame #19: 0x000000022e42ff44 SceneKit`-[SCNRenderer _drawSceneWithNewRenderer:] + 312
    frame #20: 0x000000022e43056c SceneKit`-[SCNRenderer _drawScene:] + 72
    frame #21: 0x000000022e4309bc SceneKit`-[SCNRenderer _drawAtTime:] + 760
    frame #22: 0x000000022e4dfecc SceneKit`-[SCNView _drawAtTime:] + 492
    frame #23: 0x000000022e37c15c SceneKit`__69-[NSObject(SCN_DisplayLinkExtensions) SCN_setupDisplayLinkWithQueue:]_block_invoke + 60
    frame #24: 0x000000022e4a1c50 SceneKit`__36-[SCNDisplayLink _callbackWithTime:]_block_invoke + 88
    frame #25: 0x0000000104d74778 libdispatch.dylib`_dispatch_client_callout + 20
    frame #26: 0x0000000104d82fc0 libdispatch.dylib`_dispatch_lane_barrier_sync_invoke_and_complete + 160
    frame #27: 0x000000022e4a1bb8 SceneKit`-[SCNDisplayLink _callbackWithTime:] + 268
    frame #28: 0x0000000104e082d4 GPUToolsCore`-[DYDisplayLinkInterposer forwardDisplayLinkCallback:] + 204
    frame #29: 0x000000021e53aea8 QuartzCore`CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 632
    frame #30: 0x000000021e608858 QuartzCore`display_timer_callback(__CFMachPort*, void*, long, void*) + 276
    frame #31: 0x000000021a083058 CoreFoundation`__CFMachPortPerform + 192
    frame #32: 0x000000021a0aaaf0 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 60
    frame #33: 0x000000021a0aa1e8 CoreFoundation`__CFRunLoopDoSource1 + 444
    frame #34: 0x000000021a0a4d80 CoreFoundation`__CFRunLoopRun + 2060
    frame #35: 0x000000021a0a4254 CoreFoundation`CFRunLoopRunSpecific + 452
    frame #36: 0x000000021aa8404c Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 304
    frame #37: 0x000000022e37c518 SceneKit`__49-[SCNView(SCNDisplayLink) _initializeDisplayLink]_block_invoke + 444
    frame #38: 0x000000022e37c684 SceneKit`__SCNRenderThread_start__ + 104
    frame #39: 0x0000000219d22908 libsystem_pthread.dylib`_pthread_body + 132
    frame #40: 0x0000000219d22864 libsystem_pthread.dylib`_pthread_start + 48
    frame #41: 0x0000000219d2adcc libsystem_pthread.dylib`thread_start + 4
warning: failed to set breakpoint site at 0x21931425c for breakpoint -4.1: error sending the breakpoint request
warning: failed to set breakpoint site at 0x219314530 for breakpoint -4.2: error sending the breakpoint request
warning: failed to set breakpoint site at 0x2193141b4 for breakpoint -4.3: error sending the breakpoint request
warning: failed to set breakpoint site at 0x21931fcc4 for breakpoint -5.1: error sending the breakpoint request

我没有快速调试的经验,但在我看来问题出现在某些 Metal 框架代码中的第 4-6 帧中:

 frame #4: 0x000000021c28e23c Metal`MTLReportFailure + 528    
 frame #5: 0x000000023f984108 MetalTools`-[MTLDebugDevice validateNewBufferArgs:options:] + 172
 frame #6: 0x000000023f98430c MetalTools`-[MTLDebugDevice newBufferWithBytes:length:options:] + 128

感谢任何帮助/建议!

---- 编辑 1 ----

这是一个不会产生此错误的数组:

vertices = [ //Array that should work
             SCNVector3(x: -0.06110339, y: -0.00659544, z: -0.18046863),
             SCNVector3(x: -0.06406027, y: -0.008907169, z: -0.18053372),
             SCNVector3(x: -0.06406027, y: -0.008907169, z: -0.18053372),
             SCNVector3(x: -0.06701318, y: -0.013257578, z: -0.18059872),
             SCNVector3(x: -0.069427274, y: -0.017816536, z: -0.18065183),
             SCNVector3(x: -0.07077661, y: -0.02299612, z: -0.18068156),
             SCNVector3(x: -0.07138735, y: -0.029295363, z: -0.18069498),
             SCNVector3(x: -0.07159121, y: -0.035330035, z: -0.1806995),
             SCNVector3(x: -0.06850778, y: -0.039139934, z: -0.1806316),
             SCNVector3(x: -0.059540674, y: -0.039537176, z: -0.18043421),
             SCNVector3(x: -0.04808737, y: -0.035914123, z: -0.1801821),
             SCNVector3(x: -0.045074403, y: -0.035180397, z: -0.1801158)
            ]

这是我的应用程序使用此数组时的两个屏幕截图。如您所见,多边形位于平面内,因为所有顶点位置都是从该平面上的 HitTest 中选取的。不要介意剪裁颜色,因为它是由于 z-fighting 引起的,可以通过偏移平面轻松修复:

这是生成此错误的顶点数组的示例:

vertices = [ //Array that should not work
                SCNVector3(x: 0.08866002, y: -0.007735528, z: -0.09841499),
                SCNVector3(x: 0.08873053, y: -0.014926873, z: -0.09837532),
                SCNVector3(x: 0.08873053, y: -0.014926873, z: -0.09837532),
                SCNVector3(x: 0.08846086, y: -0.024348512, z: -0.09852711),
                SCNVector3(x: 0.08749959, y: -0.034751557, z: -0.09906833),
                SCNVector3(x: 0.08527064, y: -0.043312013, z: -0.10032329),
                SCNVector3(x: 0.08125973, y: -0.049623042, z: -0.10258152),
                SCNVector3(x: 0.07674095, y: -0.054563493, z: -0.10512567),
                SCNVector3(x: 0.07041831, y: -0.057908192, z: -0.10868551),
                SCNVector3(x: 0.06373097, y: -0.058204524, z: -0.112450644),
                SCNVector3(x: 0.058445737, y: -0.057790123, z: -0.115426354),
                SCNVector3(x: 0.054485526, y: -0.05334358, z: -0.11765605),
                SCNVector3(x: 0.052902386, y: -0.04610482, z: -0.1185474),
                SCNVector3(x: 0.053534307, y: -0.036374755, z: -0.118191615),
                SCNVector3(x: 0.055890974, y: -0.027881026, z: -0.11686475),
                SCNVector3(x: 0.059101492, y: -0.022751786, z: -0.115057185),
                SCNVector3(x: 0.062345386, y: -0.02150976, z: -0.113230795),
                SCNVector3(x: 0.06506948, y: -0.022176817, z: -0.11169703)
            ]

这是使用该数组时的屏幕截图。蓝色平面是该方法起作用时的实例,但如果仔细观察,会发现一条红线。这条红线跟随上面错误数组的顶点,当使用相应几何体的多边形平面添加到场景时,它会立即使应用程序崩溃:

---- 编辑 2 ----

下面是@ARGeo 的 macOS 解决方案的代码,但稍作修改以适合我的 iOS 应用程序并使用任意数量的顶点。该代码适用于先前失败但在使用另一个顶点数组时再次失败的顶点数组。就像@ARGeo 建议的那样,我确保将此方法放在实际类中而不是扩展中,以防 MemoryLayout<Int32>.size 在扩展中使用时导致问题。

private func createPolygon(){

        func model(vertices: [SCNVector3]) -> SCNNode {

            let polyDraw = draw(vertices: vertices)

            let material = SCNMaterial()
            material.diffuse.contents = UIColor.green
            material.isDoubleSided = true

            material.diffuse.contentsTransform = .init(m11: 0.1, m12: 0,   m13: 0,  m14: 0,
                                                       m21: 0,   m22: 0.1, m23: 0,  m24: 0,
                                                       m31: 0,   m32: 0,   m33: 0,  m34: 0,
                                                       m41: 0,   m42: 0,   m43: 0,  m44: 1)

            material.diffuse.wrapS = .repeat
            material.diffuse.wrapT = .repeat
            polyDraw.materials = [material]
            let node = SCNNode(geometry: polyDraw)
            //node.scale =  SCNVector3(x: 200, y: 200, z: 200)
            sceneView.scene.rootNode.addChildNode(node)
            return node
        }

        func draw(vertices: [SCNVector3]) -> SCNGeometry {

            let normalsPerFace = 1

            var indices: [Int32] = []
            indices.append(Int32(vertices.count))

            //Add the rest of the indices 0 to vertices.count-1
            for i in 0 ... vertices.count-1 {
                indices.append(Int32(i))
            }

            let source = SCNGeometrySource(vertices: vertices)

            let vec = vertices.map { [SCNVector3](repeating: $0,
                                                                        count: normalsPerFace) }.flatMap{ $0 }
            let normals: [SCNVector3] = vec
            let normalSource = SCNGeometrySource(normals: normals)

            var cgps: [CGPoint] = []
            vertices.forEach { (vertex) in
                cgps.append(CGPoint(x: CGFloat(vertex.x), y: CGFloat(vertex.y)))
            }

            let textcoord = SCNGeometrySource(textureCoordinates: cgps)


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

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

            return SCNGeometry(sources: [source, normalSource, textcoord],                           elements: [element])
        }

        //Previous fail, now success with ARGeo's code
        let vertices = [SCNVector3(x: 0.08866002, y: -0.00773552, z: -0.09841499),
                    SCNVector3(x: 0.08873053, y: -0.01492687, z: -0.09837532),
                    SCNVector3(x: 0.08873053, y: -0.01492687, z: -0.09837532),
                    SCNVector3(x: 0.08846086, y: -0.02434851, z: -0.09852711),
                    SCNVector3(x: 0.08749959, y: -0.03475155, z: -0.09906833),
                    SCNVector3(x: 0.08527064, y: -0.04331201, z: -0.10032329),
                    SCNVector3(x: 0.08125973, y: -0.04962304, z: -0.10258152),
                    SCNVector3(x: 0.07674095, y: -0.05456349, z: -0.10512567),
                    SCNVector3(x: 0.07041831, y: -0.05790819, z: -0.10868551),
                    SCNVector3(x: 0.06373097, y: -0.05820452, z: -0.11245064),
                    SCNVector3(x: 0.05844573, y: -0.05779012, z: -0.11542635),
                    SCNVector3(x: 0.05448552, y: -0.05334358, z: -0.11765605),
                    SCNVector3(x: 0.05290238, y: -0.04610482, z: -0.11854740),
                    SCNVector3(x: 0.05353430, y: -0.03637475, z: -0.11819161),
                    SCNVector3(x: 0.05589097, y: -0.02788102, z: -0.11686475),
                    SCNVector3(x: 0.05910149, y: -0.02275178, z: -0.11505718),
                    SCNVector3(x: 0.06234538, y: -0.02150976, z: -0.11323079),
                    SCNVector3(x: 0.06506948, y: -0.02217681, z: -0.11169703)
                    ]

        _ = model(vertices: vertices)
}

上述代码失败的顶点数组示例:

vertices = [ SCNVector3(x: 0.08291423, y: -0.08406013, z: -0.60201955),
                     SCNVector3(x: 0.077855, y: -0.083336316, z: -0.60234916),
                     SCNVector3(x: 0.077855, y: -0.083336316, z: -0.60234916),
                     SCNVector3(x: 0.06817482, y: -0.08799789, z: -0.6029798),
                     SCNVector3(x: 0.055873748, y: -0.09737456, z: -0.6037812),
                     SCNVector3(x: 0.042388167, y: -0.108595274, z: -0.60465986),
                     SCNVector3(x: 0.031522393, y: -0.119523935, z: -0.6053677),
                     SCNVector3(x: 0.024102041, y: -0.13026507, z: -0.6058511),
                     SCNVector3(x: 0.021609604, y: -0.13820335, z: -0.6060136),
                     SCNVector3(x: 0.022751667, y: -0.14294992, z: -0.60593915),
                     SCNVector3(x: 0.025871918, y: -0.14491153, z: -0.6057359),
                     SCNVector3(x: 0.0338943, y: -0.14688163, z: -0.6052132),
                     SCNVector3(x: 0.041132875, y: -0.15027393, z: -0.60474163),
                     SCNVector3(x: 0.047307685, y: -0.15410759, z: -0.6043393),
                     SCNVector3(x: 0.054541387, y: -0.1566292, z: -0.603868),
                     SCNVector3(x: 0.06140149, y: -0.15919833, z: -0.60342115),
                     SCNVector3(x: 0.06551884, y: -0.16264887, z: -0.6031529)
                    ]

---- 编辑 3 ----

好的,所以我为上面的代码制作了一个 macOS 版本(这是 @ARGeo 提出的解决方案,但有一些小的变化,比如使用任意数量的顶点),即使在 iOS代码版本。但是,什么都没有呈现,我也没有收到任何我不知道原因的错误消息。添加行 cameraNode.camera?.zFar = 1000 以防 It's not visible due to clipping 时,程序会崩溃,并给出一个新的错误。如果 zFar 足够小(使用 zFar < 10 测试)它不会崩溃,在这种情况下也不会渲染多边形。错误打印是相同的 -[MTLDebugDevice validateNewBufferArgs:options:]:467: failed assertion 'Cannot create buffer of zero length.' 但调试导航器显示:

堆栈跟踪的最后一行是这样的:

* thread #8, name = 'CVDisplayLink', queue = 'com.apple.scenekit.renderingQueue.SCNView0x101306480', stop reason = signal SIGABRT
  * frame #0: 0x00007fff671b62c6 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x000000010053680d libsystem_pthread.dylib`pthread_kill + 284
    frame #2: 0x00007fff671206a6 libsystem_c.dylib`abort + 127
    frame #3: 0x00007fff670e920d libsystem_c.dylib`__assert_rtn + 324
    frame #4: 0x00007fff3fd1b68e Metal`MTLReportFailure + 567
    frame #5: 0x00007fff599f9d98 MetalTools`-[MTLDebugDevice validateNewBufferArgs:options:] + 207
    frame #6: 0x00007fff599f9f28 MetalTools`-[MTLDebugDevice newBufferWithBytes:length:options:] + 107
    frame #7: 0x00007fff462f265b SceneKit`-[SCNMTLResourceManager _bufferForData:bytesPerIndex:] + 414
    frame #8: 0x00007fff462f29e0

如果您想自己尝试一下,可以使用这里的代码。只需复制并粘贴到 macOS 项目中:


import SceneKit
import QuartzCore

class GameViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let scene = SCNScene()

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

        // This line crashes the app! But w/o it the polygon plane would probably clip and be invisible.
        cameraNode.camera?.zFar = 1000

        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.intensity = 10000
        ambientLightNode.light!.color = NSColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)

        func model(vertices: [SCNVector3]) -> SCNNode {

            let polyDraw = draw(vertices: vertices)

            let material = SCNMaterial()
            material.diffuse.contents = NSColor.green
            material.isDoubleSided = true

            material.diffuse.contentsTransform = .init(m11: 0.1, m12: 0,   m13: 0,  m14: 0,
                                                       m21: 0,   m22: 0.1, m23: 0,  m24: 0,
                                                       m31: 0,   m32: 0,   m33: 0,  m34: 0,
                                                       m41: 0,   m42: 0,   m43: 0,  m44: 1)

            material.diffuse.wrapS = .repeat
            material.diffuse.wrapT = .repeat
            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(vertices: [SCNVector3]) -> SCNGeometry {

            let normalsPerFace = 1

            var indices: [Int32] = []
            indices.append(Int32(vertices.count))

            //Add the rest of the indices 0 to vertices.count-1
            for i in 0 ... vertices.count-1 {
                indices.append(Int32(i))
            }

            let source = SCNGeometrySource(vertices: vertices)

            let vec = vertices.map { [SCNVector3](repeating: $0,
                                                  count: normalsPerFace) }.flatMap{ $0 }
            let normals: [SCNVector3] = vec
            let normalSource = SCNGeometrySource(normals: normals)

            var cgps: [CGPoint] = []
            vertices.forEach { (vertex) in
                cgps.append(CGPoint(x: CGFloat(vertex.x), y: CGFloat(vertex.y)))
            }

            let textcoord = SCNGeometrySource(textureCoordinates: cgps)


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

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

            return SCNGeometry(sources: [source, normalSource, textcoord],                           elements: [element])
        }

        //Previous fail, now success with ARGeo's code
//        let vertices = [SCNVector3(x: 0.08866002, y: -0.00773552, z: -0.09841499),
//                        SCNVector3(x: 0.08873053, y: -0.01492687, z: -0.09837532),
//                        SCNVector3(x: 0.08873053, y: -0.01492687, z: -0.09837532),
//                        SCNVector3(x: 0.08846086, y: -0.02434851, z: -0.09852711),
//                        SCNVector3(x: 0.08749959, y: -0.03475155, z: -0.09906833),
//                        SCNVector3(x: 0.08527064, y: -0.04331201, z: -0.10032329),
//                        SCNVector3(x: 0.08125973, y: -0.04962304, z: -0.10258152),
//                        SCNVector3(x: 0.07674095, y: -0.05456349, z: -0.10512567),
//                        SCNVector3(x: 0.07041831, y: -0.05790819, z: -0.10868551),
//                        SCNVector3(x: 0.06373097, y: -0.05820452, z: -0.11245064),
//                        SCNVector3(x: 0.05844573, y: -0.05779012, z: -0.11542635),
//                        SCNVector3(x: 0.05448552, y: -0.05334358, z: -0.11765605),
//                        SCNVector3(x: 0.05290238, y: -0.04610482, z: -0.11854740),
//                        SCNVector3(x: 0.05353430, y: -0.03637475, z: -0.11819161),
//                        SCNVector3(x: 0.05589097, y: -0.02788102, z: -0.11686475),
//                        SCNVector3(x: 0.05910149, y: -0.02275178, z: -0.11505718),
//                        SCNVector3(x: 0.06234538, y: -0.02150976, z: -0.11323079),
//                        SCNVector3(x: 0.06506948, y: -0.02217681, z: -0.11169703)
//        ]

        //Array which fails when the cameras zFar property
        //is too big (>10 or something).
        //If zFar is small enough it does not crash,
        //but then nothing is rendered.
        let vertices = [ SCNVector3(x: 0.08291423, y: -0.08406013, z: -0.60201955),
                         SCNVector3(x: 0.077855, y: -0.083336316, z: -0.60234916),
                         SCNVector3(x: 0.077855, y: -0.083336316, z: -0.60234916),
                         SCNVector3(x: 0.06817482, y: -0.08799789, z: -0.6029798),
                         SCNVector3(x: 0.055873748, y: -0.09737456, z: -0.6037812),
                         SCNVector3(x: 0.042388167, y: -0.108595274, z: -0.60465986),
                         SCNVector3(x: 0.031522393, y: -0.119523935, z: -0.6053677),
                         SCNVector3(x: 0.024102041, y: -0.13026507, z: -0.6058511),
                         SCNVector3(x: 0.021609604, y: -0.13820335, z: -0.6060136),
                         SCNVector3(x: 0.022751667, y: -0.14294992, z: -0.60593915),
                         SCNVector3(x: 0.025871918, y: -0.14491153, z: -0.6057359),
                         SCNVector3(x: 0.0338943, y: -0.14688163, z: -0.6052132),
                         SCNVector3(x: 0.041132875, y: -0.15027393, z: -0.60474163),
                         SCNVector3(x: 0.047307685, y: -0.15410759, z: -0.6043393),
                         SCNVector3(x: 0.054541387, y: -0.1566292, z: -0.603868),
                         SCNVector3(x: 0.06140149, y: -0.15919833, z: -0.60342115),
                         SCNVector3(x: 0.06551884, y: -0.16264887, z: -0.6031529)
                        ]

        _ = model(vertices: vertices)


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

我不知道是什么导致了这个问题,因为它似乎是一些内部渲染出了问题。我在调试方面也不是很有经验,所以我将不胜感激任何帮助,因为我无法进一步理解这一点。

最佳答案

解决方案(复制粘贴此 macOS 应用程序代码以在 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))
    }
}

有用信息:

在 3D 图形中,处理多边形几何体的最佳和最可预测的方法是最初使用三边(三角形)和四边(四边形)面。有时,在极少数情况下,您可以使用五面体,但这可能会导致您产生阴影伪像。

可能导致 SceneKit/Metal 错误的 Bad cases 是:

  • 板面
  • 非流形几何
  • 非平面(你的情况)
  • 凹面
  • “翻转”面孔,即错误的连接顺序(您的情况)
  • 有洞的脸
  • 边长为零的面
  • 等...

我应该说的更重要的一件事是:在渲染阶段,所有多边形总是变成三角形。如果渲染器或渲染引擎无法完成此转换,您将收到错误。

看看四边形如何有效地连接起来形成一个复杂的物体:

P.S. camera.zFar 用于 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 */

关于swift - 使用 SCNGeometryPrimitiveType 多边形崩溃/错误创建自定义 SCNGeometry 多边形平面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56773438/

有关swift - 使用 SCNGeometryPrimitiveType 多边形崩溃/错误创建自定义 SCNGeometry 多边形平面的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  10. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

随机推荐