ARKit/SceneKit加载USDZ模型时自定义节点名被覆盖如何解决
问题说明
基于ARKit与SceneKit开发iOS增强现实应用时,加载.usdz模型到场景后,点击模型获取节点名称,仅能返回模型自带的内部节点名,无法获取到开发者自定义设置的节点名称。
- 模型加载实现代码:
let mdlAsset = MDLAsset(url: urlPath) mdlAsset.loadTextures() let asset = mdlAsset.object(at: 0) // 提取第一个资源对象 var assetNode = SCNNode(mdlObject: asset) assetNode = SCNNode(mdlObject: asset) assetNode.name = "Node-2" sceneView.scene.rootNode.addChildNode(assetNode)
- 点击事件命中测试代码:
@objc func handleTap(recognizer: UITapGestureRecognizer){ let location = recognizer.location(in: sceneView) let results = sceneView.hitTest(location, options: nil) guard recognizer.state == .ended else { return } if results.count > 0 { let result = results[0] as SCNHitTestResult let node = result.node print(node.name) } }
- 实际运行表现:点击模型后控制台打印
Optional("Sphere_0"),为模型内置的子节点名称,不符合预期的自定义值Node-2。
故障原因
SceneKit的hitTest方法默认返回射线检测命中的最内层绑定了几何体的节点,而非外层容器节点。
通过SCNNode(mdlObject:)从MDLAsset转换生成的节点是外层容器节点,.usdz模型的实际网格、材质资源全部挂载在该容器节点的多层子节点上。代码仅给最外层容器节点设置了自定义名称,点击时射线命中的是内部承载几何体的子节点,因此返回的是模型预设的内部节点名。
修复方案
方案1:沿父节点链向上查找目标节点
拿到命中的内层节点后,逐层遍历父节点链路,匹配到设置了自定义名称的目标节点即可,该方案不会破坏原有节点结构,推荐使用:
@objc func handleTap(recognizer: UITapGestureRecognizer){ let location = recognizer.location(in: sceneView) let results = sceneView.hitTest(location, options: nil) guard recognizer.state == .ended, let firstHit = results.first else { return } var hitNode = firstHit.node // 向上遍历父节点直到找到自定义命名的节点 while let parentNode = hitNode.parent { if parentNode.name == "Node-2" { hitNode = parentNode break } hitNode = parentNode } print(hitNode.name) // 输出Optional("Node-2"),符合预期 }
方案2:统一设置模型所有节点的名称
加载模型后递归遍历所有子节点,将所有节点的名称统一设置为自定义值,适合不需要区分模型内部子节点的场景:
let mdlAsset = MDLAsset(url: urlPath) mdlAsset.loadTextures() let asset = mdlAsset.object(at: 0) let assetNode = SCNNode(mdlObject: asset) assetNode.name = "Node-2" // 递归遍历所有子节点设置名称 func setNodeNameRecursively(_ node: SCNNode, name: String) { node.name = name node.childNodes.forEach { setNodeNameRecursively($0, name: name) } } setNodeNameRecursively(assetNode, name: "Node-2") sceneView.scene.rootNode.addChildNode(assetNode)
内容的提问来源于stack exchange,提问作者Federico
相关产品推荐
相关产品推荐

