SCNKit:命中测试不会命中节点的动态修改的几何图形

SCNKit: Hit test doesn't hit node's dynamically modified geometry

我遇到的问题是 SCNView.hitTest 没有检测到我在 cpu 上动态修改的几何体的命中。

概述如下:我有一个节点使用 SCNGeometryMTLBuffer 个顶点创建:

func createGeometry(vertexBuffer: MTLBuffer, vertexCount: Int) -> SCNGeometry {
    let geometry = SCNGeometry(sources: [
        SCNGeometrySource.init(
            buffer: vertexBuffer,
            vertexFormat: .float3,
            semantic: .vertex,
            vertexCount: vertexCount,
            dataOffset: 0,
            dataStride: MemoryLayout<SIMD3<Float>>.stride),
    ], elements: [
        SCNGeometryElement(indices: ..., primitiveType: .triangles)
    ])
}


let vertexBuffer: MTLBuffer = // shared buffer
let vertexCount = ...

let node = SCNNode(geometry: createGeometry(vertexBuffer: vertexBuffer, vertexCount: vertexCount))

由于应用程序是 运行,因此我在 SceneKit 更新循环中动态修改顶点缓冲区:

// In SceneKit update function

var ptr = vertexBuffer.contents().bindMemory(to: SIMD3<Float>.self, capacity: vertexCount)

for i in 0..<vertexCount {
    ptr[i] = // modify vertex
}

这个动态几何体由 SceneKit 正确渲染。然而,当我随后尝试使用 SCNView.hitTest 针对 node 进行命中测试时,未检测到针对修改后的几何体的命中。

我可以通过在修改数据后重新创建节点的几何图形来解决这个问题:

// after updating data
node.geometry = createGeometry(vertexBuffer: vertexBuffer, vertexCount: vertexCount)

然而,这感觉像是一个 hack。

对于具有动态变化的节点,命中测试可靠工作的正确方法是什么SCNGeometry

当您执行命中测试搜索时,SceneKit 会沿着您指定的射线寻找 SCNGeometry 对象。对于光线和几何体之间的每个交点,SceneKit 创建一个命中测试结果以提供有关包含几何体的 SCNNode 对象和几何体表面上的交点位置的信息。

你的问题是,当你在渲染时修改缓冲区的内容(MTLBuffer)时,SceneKit 不知道它,因此无法更新 SCNGeometry 对象,它是用于执行命中测试。

所以我认为解决这个问题的唯一方法是重新创建您的 SCNGeometry 对象。

我认为没有 proper way 可以使命中测试在您的情况下可靠地工作。如果它不依赖于 SceneKit/Metal 呈现循环和委托模式,这显然是可能的。但由于它完全取决于它们,因此如您之前所说,重新创建 SCNGeometry 的实例是一项不切实际的昂贵操作。所以,我完全同意@HamidYusifli。