Why does ARFaceAnchor have negative Z position?

1.9k Views Asked by At

I am using ARKit's ARFaceTrackingConfiguration with ARConfiguration.WorldAlignment.camera alignment, but I found that the documentation (seemingly) does not reflect the reality;

Based on the excerpt of documentation below, I would expect that the face anchor's transform is expressed in right handed coordinate system. However, when I tried moving my head, I noticed that the Z coordinate of the face anchor is always negative (i.e. faceAnchor.transform.columns.3.z < 0). Note that moving head in the X and Y directions corresponds to expected outcome (unlike Z coordinate).

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).

I want the transform to behave as per the documentation, i.e. the Z coordinate of face anchor should be positive given that documentation says "the z-axis points out the front of the device (toward the user)". So far it seems the Z-axis points out the back of the device…

Am I missing something obvious?

I tried to repair the rotation by the following code, but I am not sure if it's correct way to fix this:

// 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
2

There are 2 best solutions below

3
On BEST ANSWER

It seems quite obvious:

When ARSession is running and ARCamera begins tracking environment, it places WorldOriginAxis in front of your face at (x: 0, y: 0, z: 0). Just check it using:

 sceneView.debugOptions = [.showWorldOrigin]

So your face's position must be at positive part of Z axis of World Coordinates.

enter image description here

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

enter image description here

And when you use ARFaceTrackingConfiguration vs ARWorldTrackingConfiguration there's two things to consider:

  • Rear Camera moves towards objects along negative Z-axes (positive X-axis is on the right).

  • Front Camera moves towards faces along positive Z-axes (positive X-axis is on the left).

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

0
On

Although I still don't know why does not the face anchor behave as described in the documentation, I can at least answer how to correct its left-handed system into the Metal- and SceneKit-friendly right-handed system (X axis to the right, Y axis up, Z axis from the screen towards user):

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
}