1

After some testings by printing faceAnchor.transform.columns.3, digging in SO: ARFaceAnchor have negative Z position? and Apple's documentation: ARFaceAnchor, I realized that the z axis is actually flipped and it is not the right-handed coordinate system as in the documentation. The ARFaceAnchor claims the coordinate:

enter image description here

the positive x direction points to the viewer’s right (that is, the face’s own left), the positive y direction points up (relative to the face itself, not to the world), and the positive z direction points outward from the face (toward the viewer)


Sarasvati has given a suggestion on doing the transformation:

    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
}

Updates based on Andy Fedoroff:

extension ViewController: ARSCNViewDelegate {
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard let faceAnchor = anchor as? ARFaceAnchor else { return }
        currentFaceAnchor = faceAnchor
        if node.childNodes.isEmpty, let contentNode = selectedContentController.renderer(renderer, nodeFor: faceAnchor) {
            node.addChildNode(contentNode)
        }
        selectedContentController.session = sceneView?.session
        selectedContentController.sceneView = sceneView
    }
    /// - Tag: ARFaceGeometryUpdate
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        guard anchor == currentFaceAnchor,
            let contentNode = selectedContentController.contentNode,
            contentNode.parent == node
            else { return }
        sceneView.session.currentFrame!.anchors.first!.transform
        print(currentFaceAnchor!.transform.columns.3)
        selectedContentController.session = sceneView?.session
        selectedContentController.sceneView = sceneView
        selectedContentController.renderer(renderer, didUpdate: contentNode, for: anchor)
    }
}

However, I printed faceAnchor.transform.columns.3 and obtained the z negative with True Depth camera. Below show x,y,z,w axis:

enter image description here

Any suggestions on how to correct the z-axis? Thank you in advance

swiftlearneer
  • 324
  • 4
  • 17

1 Answers1

3

At first, let's see what a default matrix values are.

Identity matrix

Here's an Identity 4x4 matrix with default values.

If you need additional info on elements of 4x4 matrices read this post.

 // 0  1  2  3
 ┌              ┐
 |  1  0  0  0  |  x
 |  0  1  0  0  |  y
 |  0  0  1  0  |  z
 |  0  0  0  1  |
 └              ┘

Position Mirroring

To flip entity's Z axis and X axis, in order to reorient axis from Face tracking environment to World tracking environment, use the following form of 4x4 transform matrix.

 // 0  1  2  3
 ┌              ┐
 | -1  0  0  0  |  x
 |  0  1  0  0  |  y
 |  0  0 -1  0  |  z
 |  0  0  0  1  |
 └              ┘

Rotation Mirroring

In 4x4 transform matrices rotation is a combination of scale and skew. To choose a right rotation's direction, clockwise (CW) or counter-clockwise (CCW) use + or - for cos expressions.

Here's a positive Z rotation expression (CCW).

enter image description here

Positive +cos(a):

 ┌                    ┐
 | cos -sin   0    0  |
 | sin  cos   0    0  |
 |  0    0    1    0  |
 |  0    0    0    1  |
 └                    ┘

And here's a negative Z rotation expression (CW).

enter image description here

Negative -cos(a):

 ┌                    ┐
 |-cos -sin   0    0  |
 | sin -cos   0    0  |
 |  0    0    1    0  |
 |  0    0    0    1  |
 └                    ┘
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • ! Thanks for the explanation! I am just wondering here where to apply the Position Mirroring matrix? would it be in the ARsession? – swiftlearneer Jul 22 '20 at 14:25
  • 1
    Yep, in session's ARFrame. The same way as `sceneView.session.currentFrame!.anchors.first!.transform` But you need to use this line inside a renderer(...) or session(...) delegate method. – Andy Jazz Jul 22 '20 at 14:49
  • Thanks for the response! I tried your suggestion in render(...,didUpdate,...) see the edited above and print the transform.columns.3 again and the z-axis is still negative – swiftlearneer Jul 22 '20 at 15:33
  • 1
    Could you tell me what exactly do you want? Do you want to reorient Face anchor? – Andy Jazz Jul 22 '20 at 15:35
  • I realized that the ARFaceAnchor is actually left-handed, where as the apple documentation defines it as right-handed coordinate system. I would like to correct it to the right-handed coordinate to match the documentation for using TrueDepth. "The positive x direction points to the viewer’s right (that is, the face’s own left), the positive y direction points up (relative to the face itself, not to the world), and the positive z direction points outward from the face (toward the viewer)". Now I am seeing that the z-axis is away from the face (behind the viewer) – swiftlearneer Jul 22 '20 at 15:45
  • 1
    It's right-handed relatively to viewer, but relatively to World space it's left-handed. – Andy Jazz Jul 22 '20 at 15:50
  • 1
    I think that's what the docementation and I believed to have. If that's the case should I be seeing positive z axis when I do the face tracking using the Truth Depth? When I print transform.columns.3, it is showing negative z axis instead (as the simd4 picture shown above). I just could not get it straight here. Thanks for your patience! @ Andy Fedoroff! – swiftlearneer Jul 22 '20 at 15:56
  • Thanks:)! Do you get my concern/argument here? – swiftlearneer Jul 22 '20 at 16:08
  • 1
    And I think you explain very well here. But I am just not sure what do you mean the TrueDepth camera is mirrored, as by the definition of the right-handed coordinate, I would think that we should be seeing positive z axis. – swiftlearneer Jul 22 '20 at 16:13
  • 1
    I was talking not about flipping ARCamera (it's not possible, it's obvious) but rather about flipping ARFaceAnchor or its objects that are tethered with it. So, we have discussed it in a local scope, not global. – Andy Jazz Jul 24 '20 at 08:31
  • Thank you! I am also wondering for a ARCamera related question. I tried to print the ARCamera's `sceneView.session.currentFrame!.camera.projectionMatrix`. Do you know why its always the same? I was thinking that the proejection matrix should change relative to the captured frame – swiftlearneer Jul 28 '20 at 04:23
  • 1
    Hi. I'll answer in 2 hours)) – Andy Jazz Jul 28 '20 at 04:26
  • 1
    The lowest row in 4x4 Matrix is all about `Perspective Transformations` and `Projections`. It's also not about vectors, it's about vertices! In normal state it always must be `0 0 0 1` (x, y, z, 1). If you have a simple cube in Perspective projection and you're changing `z` (in the lowest row of matrix), for example, for `1` or `-1` you'll see that a cube becomes rather a pyramid (cube compensates for Ortho projection). So `sceneView.session.currentFrame!.camera.projectionMatrix` must always be the same... Hope it helps... – Andy Jazz Jul 28 '20 at 06:25
  • Look at this discussion for additional info: https://www.gamedev.net/forums/topic/331210-bottom-row-of-4x4-matrix/ – Andy Jazz Jul 28 '20 at 06:30
  • Thanks Andy. I think my goal is still the same as my early post, which still haven't been answered yet, is to get 3D face mesh point to 2D. So I just have a question for that since the apple documentation did not say much. What exactly is the projection matrix in ARKit/secenkit? what elements does the matrix contain? Can I just simply use P'=ProjectionMatrix *3D mesh point to the points in 2D? – swiftlearneer Jul 28 '20 at 15:34
  • I am reading this: https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-introduction and alsohttps://stackoverflow.com/questions/47536580/get-camera-field-of-view-in-ios-11-arkit?noredirect=1&lq=1 and but could not get any further... – swiftlearneer Jul 28 '20 at 15:35
  • Hello Andy! Would you like how to call projection point and be used for this purpose:https://stackoverflow.com/questions/62783206/projecting-the-arkit-face-tracking-3d-mesh-to-2d-image-coordinates – swiftlearneer Jul 29 '20 at 19:41
  • Hey Andy! Could I ask you a question about `func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor)`? – swiftlearneer Aug 04 '20 at 15:20
  • 1
    Thanks Andy! I posted it here and try to describe clearly on the problem that I am facing: https://stackoverflow.com/questions/63251149/swift-obtain-and-save-the-updated-scnnode-using-projectpoint-in-scenekit – swiftlearneer Aug 04 '20 at 18:56
  • 1
    Sorry @swiftlearneer, at the moment I have no mac with me (I told you I'm on vacation). So I can't test it now. – Andy Jazz Aug 05 '20 at 08:03
  • Hey Andy! I am still not too sure why `sceneView.session.currentFrame!.camera.projectionMatrix` must always be the same. I am not too sure I am following. For ARFacetracking, if the face mesh moves, I am wondering why projection matrix is not changing as I saw. Could you explain what the pojection matrix is in the ARkit/Scenekit and why its not changing for face tracking? – swiftlearneer Aug 06 '20 at 15:04
  • 1
    Hey! Read this article, please! https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrices-what-you-need-to-know-first It's difficult to describe it in two words))). – Andy Jazz Aug 06 '20 at 15:36
  • Thanks for the response, Andy! And I also just reading this: https://www.raywenderlich.com/728-metal-tutorial-with-swift-3-part-2-moving-to-3d for metal rendering as well. I understand that there are two views: orthographic and perspective and the "Metal renders everything using orthographic projection, so you need to transform the scene to a perspective appearance. This calls for a matrix that describes perspective projection." – swiftlearneer Aug 06 '20 at 16:25
  • Does the pojection Matrix in ARkit means the same here "perspective projection matrix remaps a 3D point's coordinates to its "2D" position on the screen in NDC space"? So if I take my 3D point and multiply by the obtain projection matrix, does it give me the 2D point in NDC space? – swiftlearneer Aug 06 '20 at 16:35
  • As I said earlier, sorry but I'm not good at Metal ((( – Andy Jazz Aug 06 '20 at 18:45
  • That's okay Andy! I will keep looking at it! No worries! – swiftlearneer Aug 06 '20 at 18:49
  • Hi Andy! Quick question here, do you know is it possible to center the user's face position whenever he/she looks at the front camera for face-tracking? – swiftlearneer Aug 24 '20 at 02:54
  • 1
    Hi @swiftlearneer, If you mean you need to move facial-world axis – technically it's possible but only when user's face is fully inside a frame. If user's face isn't inside a frame – it's not useful to center anything. – Andy Jazz Aug 24 '20 at 03:28
  • Hi Andy, thanks so much for the response! Yes, I meant when the user's face is inside the ARscene view. The purpose of it is to try to keep the position consistent whenever the user's looking at the front camera, center at the ARscene view – swiftlearneer Aug 24 '20 at 03:43
  • Do you have time to take a look at this:https://stackoverflow.com/questions/67305259/projectpoint-for-getting-2d-image-coordinates-in-arkit?noredirect=1#comment118971269_67305259 – swiftlearneer Apr 29 '21 at 22:58
  • Hi @swiftlearneer, sorry, I have a busy schedule until mid-May... – Andy Jazz Apr 30 '21 at 06:51