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

如何将ARKit中的lookAtPoint转换为屏幕坐标点?

ARKit视线点转屏幕坐标实现方案

核心思路:正确转换世界空间点到屏幕像素坐标

lookAtPoint是ARFaceAnchor提供的世界空间坐标点,直接用projectPoint时需要注意完整转换流程——该方法返回的是标准化设备坐标(NDC),需进一步映射为屏幕像素坐标。

完整代码实现(UIKit红点示例)

在ARSCNViewDelegate的代理方法中处理人脸锚点更新:

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let faceAnchor = anchor as? ARFaceAnchor else { return }
    
    // 1. 获取世界空间的视线点
    let lookAtWorldPoint = faceAnchor.lookAtPoint
    
    // 2. 转换为标准化设备坐标(NDC)
    let ndcPoint = sceneView.projectPoint(lookAtWorldPoint)
    
    // 3. 将NDC坐标转为屏幕像素坐标
    let bounds = sceneView.bounds
    let screenX = (ndcPoint.x + 1) * bounds.width / 2
    let screenY = (1 - ndcPoint.y) * bounds.height / 2
    
    // 4. 更新红点UI位置
    redDotView.center = CGPoint(x: screenX, y: screenY)
}

常见失败原因排查

  • 无效的人脸锚点:确保已启动ARFaceTrackingConfiguration,且设备成功捕捉到人脸(可通过session(_:didAdd:)确认锚点添加)
  • 未转换NDC坐标:直接使用ndcPoint.x/y会得到[-1,1]范围的值,必须映射到屏幕宽高区间
  • 视线点在相机后方:若lookAtPoint的z值为负(相对于相机),projectPoint会返回无效坐标,可先判断ndcPoint.z是否在[0,1]范围内

用双眼变换实现更精准的视线追踪

如果lookAtPoint精度不足,可通过左右眼的变换矩阵计算视线射线,再与屏幕平面求交点:

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let faceAnchor = anchor as? ARFaceAnchor else { return }
    guard let cameraNode = sceneView.pointOfView else { return }
    
    // 获取双眼的世界空间变换
    let leftEyeWorldTransform = node.simdTransform * faceAnchor.leftEyeTransform
    let rightEyeWorldTransform = node.simdTransform * faceAnchor.rightEyeTransform
    
    // 计算双眼平均位置与视线方向
    let leftEyePos = leftEyeWorldTransform.columns.3
    let rightEyePos = rightEyeWorldTransform.columns.3
    let avgEyePos = (leftEyePos + rightEyePos) / 2
    
    let leftEyeDir = simd_normalize(-leftEyeWorldTransform.columns.2)
    let rightEyeDir = simd_normalize(-rightEyeWorldTransform.columns.2)
    let avgEyeDir = simd_normalize(leftEyeDir + rightEyeDir)
    
    // 计算视线与1米远平面的交点(可自定义距离)
    let targetZ = 1.0
    let cameraZ = cameraNode.simdTransform.columns.3.z
    let t = (targetZ - cameraZ) / avgEyeDir.z
    let hitWorldPoint = avgEyePos + avgEyeDir * t
    
    // 转换为屏幕坐标(同之前的流程)
    let ndcPoint = sceneView.projectPoint(SCNVector3(hitWorldPoint))
    let bounds = sceneView.bounds
    let screenX = (ndcPoint.x + 1) * bounds.width / 2
    let screenY = (1 - ndcPoint.y) * bounds.height / 2
    
    redDotView.center = CGPoint(x: screenX, y: screenY)
}

注意事项

  • 仅支持iPhone X及以上设备(需前置深度摄像头)
  • 若红点是SceneKit节点,无需转屏幕坐标,直接设置node.position = lookAtWorldPoint即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:23:25