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

ARKit中基于3D坐标计算2D箭头指向的问题及修正方案

用2D箭头引导ARKit相机朝向3D物体的实现方案

我最近在做ARKit开发时,遇到了这么个需求:已知相机和3D物体的笛卡尔坐标,需要用UIImageView做一个2D箭头,指示用户移动相机的方向,引导他们看到目标3D物体。最开始我尝试用反正切函数计算箭头旋转角度,但发现因为坐标系的问题,结果完全不对。

最初的尝试代码

func redirectArrow(bee: SCNNode, arrow: UIImageView) {
    let (direction, position) = self.getUserVector()
    let dx = bee.position.x - position.x
    let dy = bee.position.y - position.y
    let arctangent = atan(dy/dx)
    arrow.transform = CGAffineTransform(rotationAngle: CGFloat(arctangent))
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        self.redirectArrow(bee: bee, arrow: arrow)
    }
}

func getUserVector() -> (SCNVector3, SCNVector3) {
    // (direction, position)
    if let frame = self.sceneView.session.currentFrame {
        let mat = SCNMatrix4(frame.camera.transform)
        // 4x4 transform matrix describing camera in world space
        let dir = SCNVector3(-1 * mat.m31, -1 * mat.m32, -1 * mat.m33)
        // orientation of camera in world space
        let pos = SCNVector3(mat.m41, mat.m42, mat.m43)
        // location of camera in world space
        return (dir, pos)
    }
    return (SCNVector3(0, 0, -1), SCNVector3(0, 0, -0.2))
}

问题根源

一开始的思路错在直接用3D世界坐标的差值计算角度——我们要的是屏幕2D坐标系下的方向,不是3D世界空间的方向。用3D坐标算出来的角度根本没法对应到屏幕上的箭头指向。

修正后的实现方案

感谢mnuages的解答,我调整了代码,核心是用ARKit的projectPoint(_:)方法把3D坐标转成屏幕2D坐标,再基于屏幕坐标的差值计算箭头旋转角度:

func redirectArrow(bee: SCNNode, arrow: UIImageView) {
    let (direction, position) = self.getUserVector()
    let bee2DPosition = sceneView.projectPoint(bee.position)
    let world2DPosition = sceneView.projectPoint(direction)
    let dx = bee2DPosition.x - world2DPosition.x
    let dy = bee2DPosition.y - world2DPosition.y
    var arctangent: Float = atan(dy/dx)
    if dx < 0 {
        arctangent += Float(Double.pi)
    }
    arrow.transform = CGAffineTransform(rotationAngle: CGFloat(arctangent))
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        self.redirectArrow(bee: bee, arrow: arrow)
    }
}

关键细节说明

  • projectPoint(_:)会把3D世界空间的点转换成屏幕坐标系的点(原点在屏幕左下角,x轴向右,y轴向上);
  • 计算屏幕坐标差值后,用atan(dy/dx)得到基础角度,同时要处理dx<0的情况,加上π修正角度象限,确保箭头指向正确;
  • 通过定时调用更新函数,实现箭头方向的实时刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:02:51