You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:19:10