iOS Swift新手求助:ARKit中如何通过HitTest区分检测平面与数字对象?
解决ARKit中点击区分检测平面与已放置对象的问题
Hey there! 作为ARKit新手,你这个区分平面和放置对象的问题其实是入门阶段非常典型的场景,你的思路方向完全正确——就是通过两次hitTest的优先级区分,先检查是否点击到了我们自己放置的3D对象,再去检测ARKit识别的平面。下面我把这个逻辑补全并给你拆解清楚:
核心逻辑思路
- 第一步:点击触发时,优先用
hitTest(_:options:)检测已放置的3D节点,如果命中就处理对象的选中、平移、旋转或删除操作 - 第二步:如果没命中任何自定义对象,再用
hitTest(_:types:)检测ARKit识别的水平面,处理新对象的放置逻辑
完整代码实现
@objc func tapped(_ gesture: UITapGestureRecognizer) { guard let sceneView = gesture.view as? ARSCNView else { return } let touchLocation = gesture.location(in: sceneView) // 1. 先检测是否点击到了已放置的自定义对象 let nodeHitResults = sceneView.hitTest(touchLocation, options: [ SCNHitTestOption.boundingBoxOnly: true, // 检测包围盒提升性能,不需要精确点击几何体时推荐开启 SCNHitTestOption.searchMode: SCNHitTestSearchMode.all.rawValue ]) if let hitResult = nodeHitResults.first { let targetNode = hitResult.node // 这里可以根据需求处理对象操作:比如标记选中、触发平移/旋转/删除 targetNode.geometry?.firstMaterial?.diffuse.contents = UIColor.orange // 示例:改变颜色标记选中 print("选中了已放置对象:\(targetNode.name ?? "未命名节点")") return // 命中对象后,直接返回不再处理平面检测 } // 2. 未命中对象时,检测ARKit识别的水平面 let planeHitResults = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent) if let hitResult = planeHitResults.first { // 计算平面上的放置位置 let placementPosition = SCNVector3( hitResult.worldTransform.columns.3.x, hitResult.worldTransform.columns.3.y, hitResult.worldTransform.columns.3.z ) // 示例:创建一个简单立方体并放置 let cubeNode = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)) cubeNode.position = placementPosition cubeNode.name = "UserPlacedCube" // 给节点命名,方便后续识别过滤 sceneView.scene.rootNode.addChildNode(cubeNode) print("在平面上放置了新对象") } }
关键细节说明
- hitTest优先级:必须先检测自定义节点再检测平面——因为当对象放在平面上时,点击位置会同时覆盖两者,优先响应对象操作符合用户预期
- 节点识别优化:给自定义对象节点设置
name属性,后续可以在hitTest结果里过滤掉ARKit自带的平面节点(比如只处理name包含特定标识的节点) - 平面检测类型:
.existingPlaneUsingExtent会使用ARKit已识别平面的实际范围检测,适合精准放置;如果需要支持在平面扩展区域放置,可以改用.existingPlaneUsingGeometry - 性能优化:开启
boundingBoxOnly选项后,检测只针对节点的包围盒,比检测整个几何体表面快很多,适合大多数操作场景
进阶提示
如果要实现对象的平移、旋转功能,可以在选中节点后,给ARSCNView添加UIPanGestureRecognizer、UIRotationGestureRecognizer,并将手势事件绑定到选中的节点上进行变换操作。
内容的提问来源于stack exchange,提问作者Sourabh
相关产品推荐
相关产品推荐

