为什么 ARFaceAnchor 有负 Z 位置?

Why does ARFaceAnchor have negative Z position?

我正在使用 ARKit 的 ARFaceTrackingConfigurationARConfiguration.WorldAlignment.camera 对齐,但我发现文档(貌似)没有反映现实;

根据下面的文档摘录,我希望面部锚点的 transform 是用右手坐标系表示的。但是,当我尝试移动头部时,我注意到面部锚点的 Z 坐标始终为负(即 faceAnchor.transform.columns.3.z < 0)。请注意,在 X 和 Y 方向上移动头部对应于预期结果(与 Z 坐标不同)。

Camera alignment defines a coordinate system based on the native sensor orientation of the device camera. Relative to a AVCaptureVideoOrientation.landscapeRight-oriented camera image, the x-axis points to the right, the y-axis points up, and the z-axis points out the front of the device (toward the user).

我希望 transform 按照文档的方式运行,即面锚的 Z 坐标应该是正的,因为文档说“z 轴指向设备(朝向用户)”。到目前为止,Z 轴似乎指向设备的 back

我是不是遗漏了什么明显的东西?

我尝试通过以下代码修复旋转,但我不确定修复此问题的方法是否正确:

// Repair rotation
let oldFaceRotation = simd_quatf(face.transform) // get quaternion from 
let repairedFaceRotation = simd_quatf(ix: oldFaceRotation.axis.y, iy: oldFaceRotation.axis.x, iz: -oldFaceRotation.axis.z, r: oldFaceRotation.real)

// Repair translation
var repairedPosition = face.transform.columns.3
repairedPosition.z *= -1

// Combine
var correctedFaceTransform = float4x4(repairedFaceRotation)
correctedFaceTransform.columns.3 = repairedPosition

好像很明显:

当 ARSession 为 运行 且 ARCamera 开始跟踪环境时,它会将 WorldOriginAxis 放在你的脸前(x: 0, y: 0, z: 0)。只需使用以下方法检查它:

 sceneView.debugOptions = [.showWorldOrigin]

所以你的脸的位置必须在世界坐标positive part of Z axis

Thus, ARFaceAnchor will be placed at positive Z-axis direction, as well.

当您使用 ARFaceTrackingConfigurationARWorldTrackingConfiguration 时,有两件事需要考虑:

  • Rear Camera沿负Z轴向物体移动(正X轴在右边) .

  • 前置摄像头沿正Z轴朝向面部移动(正X轴在左侧) .

Hence, when you are "looking" through TrueDepth Camera, a 4x4 Matrix is mirrored.

虽然我仍然不知道为什么面部锚点的行为与文档中描述的不一样,但我至少可以回答如何将其左手系统修正为Metal 和 SceneKit 友好的右手系统(X 轴向右,Y 轴向上,Z 轴从屏幕朝向用户):

func faceAnchorPoseToRHS(_ mat: float4x4) -> float4x4 {
    let correctedPos = float4(x: mat.columns.3.x, y: mat.columns.3.y, z: -mat.columns.3.z, w: 1)

    let quat = simd_quatf(mat)
    let newQuat = simd_quatf(angle: -quat.angle, axis: float3(quat.axis.x, quat.axis.y, -quat.axis.z))
    var newPose = float4x4(newQuat)
    newPose.columns.3 = correctedPos

    return newPose
}