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

ARKit开发AR健身应用如何检测机器人手部触碰ImageView黄点

ARKit场景下3D模型与2D UI元素碰撞检测解决方案

以下两种方案适配不同开发需求,可根据你的应用实际场景选择:

方案1:3D空间坐标映射法(精度最高,推荐AR健身场景使用)

核心逻辑是把2D的黄色圆点坐标映射到AR 3D世界空间,用原生物理碰撞体系做检测:

  • 第一步:用ARSCNView的unprojectPoint(_:ontoPlane:)方法,把UIImageView的center屏幕坐标,转换为你健身动作对应的平面(比如用户前方的交互平面)上的3D世界坐标
  • 第二步:给转换后的3D点添加一个半透明/完全透明的球形碰撞节点,半径可根据黄色圆点的实际大小调整;同时给机器人手部节点添加运动类型的物理碰撞体,设置匹配的碰撞掩码
  • 第三步:实现SCNPhysicsContactDelegate的碰撞回调,直接监听碰撞触发事件即可

代码示例:

// 转换黄色圆点坐标到AR 3D世界空间
let dotScreenPos = yellowDotImageView.center
let dot3DPos = sceneView.unprojectPoint(SCNVector3(Float(dotScreenPos.x), Float(dotScreenPos.y), 0.99), ontoPlane: interactivePlane)

// 给圆点添加碰撞节点
let dotCollider = SCNNode(geometry: SCNSphere(radius: 0.05))
dotCollider.position = dot3DPos
dotCollider.physicsBody = SCNPhysicsBody(type: .static, shape: nil)
dotCollider.physicsBody?.categoryBitMask = 1 << 0
dotCollider.physicsBody?.contactTestBitMask = 1 << 1
dotCollider.geometry?.firstMaterial?.diffuse.contents = UIColor.clear
sceneView.scene.rootNode.addChildNode(dotCollider)

// 给机器人手部添加碰撞体
robotHandNode.physicsBody = SCNPhysicsBody(type: .kinematic, shape: nil)
robotHandNode.physicsBody?.categoryBitMask = 1 << 1
robotHandNode.physicsBody?.contactTestBitMask = 1 << 0

// 碰撞触发回调
func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
    if (contact.nodeA.categoryBitMask | contact.nodeB.categoryBitMask) == (1<<0 | 1<<1) {
        // 执行得分、反馈等自定义逻辑
        print("手部已触碰黄色得分点")
    }
}

方案2:2D投影检测法(实现更简单,适合轻量交互场景)

核心逻辑是反过来把机器人手部的3D坐标投影到2D屏幕,直接判断坐标是否在黄色圆点范围内:

  • 直接在SceneKit的每帧更新回调里,调用ARSCNView的projectPoint(_:)方法把机器人手部的3D世界坐标转成2D屏幕坐标
  • 判断转换后的2D坐标是否落在UIImageView的bounds范围内即可

代码示例:

// 每帧更新时检测
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        // 过滤手部在摄像头背面的无效情况
        let hand3DPos = self.robotHandNode.worldPosition
        let projectedPos = self.sceneView.projectPoint(hand3DPos)
        guard projectedPos.z < 1 else { return }
        // 转换坐标判断是否在圆点范围内
        let handScreenPos = CGPoint(x: CGFloat(projectedPos.x), y: CGFloat(projectedPos.y))
        if self.yellowDotImageView.bounds.contains(self.yellowDotImageView.convert(handScreenPos, from: self.view)) {
            // 执行得分、反馈等自定义逻辑
            print("手部已触碰黄色得分点")
        }
    }
}

注意如果你的黄色圆点是跟随AR空间位置移动的,优先选方案1;如果圆点是固定在屏幕上的UI元素,方案2的开发成本更低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 23:57:02