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

ARFaceTrackingConfiguration下前置True Depth相机是否支持射线检测?

前置True Depth相机在ARFaceTrackingConfiguration下的射线检测问题解答

核心结论:前置True Depth相机在ARFaceTrackingConfiguration模式下不支持你当前使用的ARRaycastQuery射线检测,原因和替代方案如下:

为什么现有代码无法工作

ARFaceTrackingConfiguration的核心是面部追踪,它的会话逻辑和后置相机的ARWorldTrackingConfiguration完全不同:

  • 后置World模式会持续重建环境平面、追踪空间锚点,raycast依赖这些环境数据(比如你指定的.estimatedPlane)返回结果;
  • 前置Face模式仅维护面部的3D Mesh数据和ARFaceAnchor锚点,不会生成任何环境平面数据,所以基于.estimatedPlane的射线检测自然返回空数组。

True Depth相机的深度数据确实存在,但仅围绕追踪到的面部,不会扩展到环境空间。

实现3D两点距离的替代方案

你的目标是获取3D空间中两点距离,可基于ARFaceAnchor的面部Mesh数据实现自定义射线检测,或直接利用面部顶点坐标计算:

方案1:自定义射线与面部Mesh的相交检测

通过遍历ARFaceAnchor提供的面部三角形Mesh,实现射线与三角形的相交计算(比如经典的Möller–Trumbore算法),得到交点后即可计算距离。示例代码如下:

// 在ARSCNViewDelegate方法中获取面部追踪数据
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let faceAnchor = anchor as? ARFaceAnchor else { return }
    
    // 将屏幕中心转换为3D射线
    let screenCenter = sceneView.center
    let nearPoint = sceneView.unprojectPoint(SCNVector3(screenCenter.x, screenCenter.y, 0))
    let farPoint = sceneView.unprojectPoint(SCNVector3(screenCenter.x, screenCenter.y, 1))
    let rayDirection = (farPoint - nearPoint).normalized()
    
    // 遍历面部Mesh的三角形,检测射线交点
    let geometry = faceAnchor.geometry
    let vertices = geometry.vertices
    let indices = geometry.triangleIndices
    
    for i in stride(from: 0, to: indices.count, by: 3) {
        let v1 = vertices[Int(indices[i])]
        let v2 = vertices[Int(indices[i+1])]
        let v3 = vertices[Int(indices[i+2])]
        
        if let intersectionPoint = rayIntersectsTriangle(origin: nearPoint, direction: rayDirection, v1: v1, v2: v2, v3: v3) {
            // 示例:计算交点到面部原点的距离
            let distance = intersectionPoint.distance(to: SCNVector3Zero)
            print("3D距离:\(distance)米")
            break
        }
    }
}

// 辅助工具方法
extension SCNVector3 {
    func normalized() -> SCNVector3 {
        let length = sqrt(x*x + y*y + z*z)
        return SCNVector3(x/length, y/length, z/length)
    }
    
    func distance(to vector: SCNVector3) -> Float {
        let dx = x - vector.x
        let dy = y - vector.y
        let dz = z - vector.z
        return sqrt(dx*dx + dy*dy + dz*dz)
    }
    
    static func -(left: SCNVector3, right: SCNVector3) -> SCNVector3 {
        return SCNVector3(left.x - right.x, left.y - right.y, left.z - right.z)
    }
    
    static func +(left: SCNVector3, right: SCNVector3) -> SCNVector3 {
        return SCNVector3(left.x + right.x, left.y + right.y, left.z + right.z)
    }
    
    static func *(left: SCNVector3, right: Float) -> SCNVector3 {
        return SCNVector3(left.x * right, left.y * right, left.z * right)
    }
    
    func cross(_ vector: SCNVector3) -> SCNVector3 {
        return SCNVector3(
            y * vector.z - z * vector.y,
            z * vector.x - x * vector.z,
            x * vector.y - y * vector.x
        )
    }
    
    func dot(_ vector: SCNVector3) -> Float {
        return x * vector.x + y * vector.y + z * vector.z
    }
}

// Möller–Trumbore射线三角形相交算法
func rayIntersectsTriangle(origin: SCNVector3, direction: SCNVector3, v1: SCNVector3, v2: SCNVector3, v3: SCNVector3) -> SCNVector3? {
    let edge1 = v2 - v1
    let edge2 = v3 - v1
    let h = direction.cross(edge2)
    let a = edge1.dot(h)
    
    if a > -0.00001 && a < 0.00001 {
        return nil // 射线与平面平行
    }
    
    let f = 1/a
    let s = origin - v1
    let u = f * s.dot(h)
    
    if u < 0 || u > 1 {
        return nil
    }
    
    let q = s.cross(edge1)
    let v = f * direction.dot(q)
    
    if v < 0 || u + v > 1 {
        return nil
    }
    
    let t = f * edge2.dot(q)
    if t > 0.00001 {
        return origin + direction * t
    } else {
        return nil
    }
}

方案2:直接使用面部顶点坐标计算

如果你的两个目标点都是面部上的特征点(比如鼻尖、眼角),可以直接通过ARFaceAnchor的blendShapes或Mesh顶点索引获取对应3D坐标,再计算两点距离,无需射线检测。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 14:43:28