SCNKit:命中测试不会命中节点的动态修改的几何图形
SCNKit: Hit test doesn't hit node's dynamically modified geometry
我遇到的问题是 SCNView.hitTest
没有检测到我在 cpu 上动态修改的几何体的命中。
概述如下:我有一个节点使用 SCNGeometry
从 MTLBuffer
个顶点创建:
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。
我遇到的问题是 SCNView.hitTest
没有检测到我在 cpu 上动态修改的几何体的命中。
概述如下:我有一个节点使用 SCNGeometry
从 MTLBuffer
个顶点创建:
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。