3

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
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
sarasvati
  • 792
  • 12
  • 30

2 Answers2

4

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.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 1
    I tried adding `.showWorldOrigin`, but wasn't able to see the origin in live view, sample code [here](https://pastebin.com/mmavCVnw). Based on [Apple's documentation](https://developer.apple.com/documentation/arkit/arconfiguration/worldalignment/camera), the origin should be inside the camera sensor which would explain it. But there is one more problem: from the diagram you posted, it seems that when I would move my head to the right, X would decrease, but in reality X value increases. In other words: `ARFaceAnchor`'s coordinate system seems to be left-handed, but your diagram is right-handed. – sarasvati Aug 23 '19 at 20:52
  • 1
    Please try printing the `ARFaceAnchor`'s `transform.column.3` vector and try moving your head to see how do X, Y and Z coordinates increase. – sarasvati Aug 23 '19 at 20:54
  • Hi @sarasvati! I am using ARFaceAnchor and I think I am facing the same problem. Could you explain where to call the func faceAnchorPoseToRHS! Thanks! – swiftlearneer Jul 21 '20 at 00:40
1

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
}
sarasvati
  • 792
  • 12
  • 30