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

SceneKit中检测AR追踪生成的3D汽车模型触摸事件

解决ARKit中仅点击3D汽车模型时播放音效的问题

核心思路

通过SceneKit的hitTest方法精准检测触摸点对应的3D节点,判断是否为目标汽车模型后再触发音效播放,替代原有的全局屏幕触摸检测逻辑。

步骤1:给汽车节点添加唯一标识

在渲染汽车模型的renderer(_:nodeFor:)方法中,给每个汽车节点设置唯一name属性,方便后续识别:

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    let node = SCNNode()
 
    if let imageAnchor = anchor as? ARImageAnchor {
        
        let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height)
        plane.firstMaterial?.diffuse.contents = UIColor(white: 1.0, alpha: 0.75)
        let planeNode = SCNNode(geometry: plane)
        planeNode.name = "trackingPlane" // 给追踪平面命名,后续可排除点击
        planeNode.eulerAngles.x = -.pi/2
        node.addChildNode(planeNode)
        
        if imageAnchor.referenceImage.name! == "mercedes2019coupe" {
            let mercedesScene = SCNScene(named: "art.scnassets/mercedesAR.scn")!
            let mercedesNode = mercedesScene.rootNode.childNodes.first!
            mercedesNode.name = "mercedesCar" // 设置奔驰节点唯一标识
            mercedesNode.eulerAngles.x = .pi/2
            mercedesNode.eulerAngles.z = -.pi/2
            let yShift = (mercedesNode.boundingBox.max.y - mercedesNode.boundingBox.min.y) / 2
            mercedesNode.position.y += yShift * 0.05
            planeNode.addChildNode(mercedesNode)
        }
        if imageAnchor.referenceImage.name! == "audir8" {
            let audiScene = SCNScene(named: "art.scnassets/audi.scn")!     
            let audiNode = audiScene.rootNode.childNodes.first!
            audiNode.name = "audiCar" // 设置奥迪节点唯一标识
            audiNode.eulerAngles.x = .pi/2
            audiNode.eulerAngles.z = -.pi/2
            let yShift = (audiNode.boundingBox.max.y - audiNode.boundingBox.min.y) / 2
            audiNode.position.y += yShift * 0.1
            planeNode.addChildNode(audiNode)
        }
    }
    return node
}

步骤2:修改触摸检测逻辑,精准识别汽车节点

替换原有的touchesBegan方法,使用hitTest检测触摸点对应的3D节点:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else { return }
    let touchLocation = touch.location(in: sceneView)
    
    // 执行SceneKit节点命中检测,优先检测节点的 bounding box
    let hitResults = sceneView.hitTest(touchLocation, options: [
        SCNHitTestOption.searchMode: SCNHitTestSearchMode.all.rawValue,
        SCNHitTestOption.boundingBoxOnly: true,
        SCNHitTestOption.ignoreHiddenNodes: true // 忽略隐藏节点
    ])
    
    // 遍历检测结果,匹配目标汽车节点
    for result in hitResults {
        guard let nodeName = result.node.name else { continue }
        switch nodeName {
        case "mercedesCar":
            playMercedesSound() // 播放奔驰专属音效
            return
        case "audiCar":
            playAudiSound() // 播放奥迪专属音效
            return
        default:
            continue // 忽略其他节点(如追踪平面)
        }
    }
}

额外注意事项

  • 确保sceneView的isUserInteractionEnabled属性为true(默认开启,若手动修改过需恢复)
  • 若不需要显示追踪平面,可设置planeNode.isHidden = true,避免误触
  • 如果汽车模型面结构复杂,可将SCNHitTestOption.boundingBoxOnly改为false,但会略微降低检测性能

内容的提问来源于stack exchange,提问作者Arcee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 06:06:28