SceneKit人体模型点击无法识别Geometry Element,需获取对应几何元素
看起来你遇到的核心问题是:单个SCNNode包含多个Geometry Element,但点击时无法直接拿到对应Element的预期名称,只能看到自动生成的节点名(比如body-splitcontainer-splitX),而且geometryIndex返回始终为0。下面是具体的解决思路和修改方案:
1. 先确认模型的Geometry Element结构
首先你需要验证你的模型里的Geometry Element是否真的带有你预期的名称(比如body-Element0)。在视图加载完成后,打印节点的Geometry Elements信息:
// 假设你的人体模型节点是humanNode if let geometry = humanNode.geometry { print("Total Geometry Elements: \(geometry.elements.count)") geometry.elements.enumerated().forEach { index, element in print("Element \(index) Name: \(element.name ?? "Unnamed")") } }
如果打印出来的Element名称都是Unnamed或者类似body-splitcontainer-splitX的自动命名,那说明你的模型在导出时没有保留Geometry Element的自定义名称,需要回到建模工具(比如Blender、Maya)里,给每个对应身体部位的Mesh/Element设置好名称,再重新导出为SceneKit支持的格式(比如.dae或.scn)。
2. 修改Hit Test的配置和结果处理
默认的hitTest可能没有正确返回Geometry Element的索引,或者你的代码没有正确使用这个索引。修改你的handleTap方法,重点关注SCNHitTestResult的geometryIndex属性,并用它从节点的Geometry中获取对应的Element:
@objc func handleTap(_ gestureRecognize: UIGestureRecognizer) { let scnView = self.view as! SCNView let p = gestureRecognize.location(in: scnView) // 设置hitTest选项,确保检测到所有层级的Geometry Element let hitTestOptions: [SCNHitTestOption: Any] = [ .searchMode: SCNHitTestSearchMode.all, // 搜索所有可见的Geometry .ignoreHiddenNodes: true ] let hitResults = scnView.hitTest(p, options: hitTestOptions) if let result = hitResults.first { let tappedNode = result.node // 获取对应的Geometry Element if let geometry = tappedNode.geometry, result.geometryIndex < geometry.elements.count { let tappedElement = geometry.elements[result.geometryIndex] let elementName = tappedElement.name ?? "Unnamed Element" print("Tapped Geometry Element: \(elementName)") } // 获取材质(你的原有逻辑可以保留) if let material = result.node.geometry?.firstMaterial { print("Material Name: \(material.name ?? "Unnamed Material")") // 高亮动画逻辑(保留) SCNTransaction.begin() SCNTransaction.animationDuration = 0.5 SCNTransaction.completionBlock = { SCNTransaction.begin() SCNTransaction.animationDuration = 0.5 material.emission.contents = UIColor.black SCNTransaction.commit() } material.emission.contents = UIColor.yellow SCNTransaction.commit() } } }
3. 为什么之前geometryIndex一直为0?
- 可能是模型导出时,所有的Geometry Element被合并成了一个,导致不管点击哪里,索引都是0。这种情况需要回到建模工具,将身体各部位拆分为独立的Geometry Element并命名,再导出。
- 也可能是默认的
hitTest选项没有设置searchMode为.all,导致只检测到节点层级,没有深入到Element层级。
额外提示
如果你的模型在建模时是将不同身体部位作为独立的SCNNode(而不是单个节点下的多个Element),那点击时直接通过result.node.name就能拿到部位名称,这种方式会更简单。如果必须用单个节点下的多个Element,就按照上面的方案处理。
内容的提问来源于stack exchange,提问作者Faran

