0

I get a Json from ThreeJs that look like this :

{
    "scene": {
        "metadata": {
            ..
        },
        "geometries": [
            ..
        "materials": [
            ...
        "object": {
            "name": "Scene",
            "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
            "children": [
                {
                    "name": "scene (1).glb",
                    "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
                    "children": [
                        {
                            "name": "Box",
                            "matrix": [1.5,0,0,0,0,1.5,0,0,0,0,1.5,0,1,1,1,1],
                            "children": [
                                {
                                    "name": "Box",
                                    "matrix": [0.5,0,0,0,0,0.5,0,0,0,0,0.5,0,2,2,2,1],
                                    "children": [
                                        {
                                            "name": "Box",
                                            "matrix": [1,0,0,0,0,0.707107,0.707107,0,0,-0.707107,0.707107,0,-2,0,2,1],
                                        }]
                                }]
                        }]
                }]
        }
    },
}

The scene in ThreeJS editor look like this : enter image description here

And I want to have the same result in Unity. The way I'm doing this so far is to get the ThreeJS objects matrix and convert it to position, rotation and scale in Unity; like this :

 private void GetTransformFromMatrix(double[] matrix, out Vector3 position, out Quaternion rotation, out Vector3 scale)
    {
            // Matrix understanding so far: 
            { scaleX, forwardX, upwardX, 0,0, scaleY / forwardY, upwardY, 0,0,  forwardZ, upwardZ, scaleZ, 0, posX, posY, posZ, 1}
  
            position = new Vector3(Convert.ToSingle(matrix[12]), Convert.ToSingle(matrix[13]), Convert.ToSingle(matrix[14]));
            rotation = Quaternion.LookRotation(new Vector3(Convert.ToSingle(matrix[1]), Convert.ToSingle(matrix[5]), Convert.ToSingle(matrix[9])), new Vector3(Convert.ToSingle(matrix[2]), Convert.ToSingle(matrix[6]), Convert.ToSingle(matrix[10])));
            rotation.eulerAngles = new Vector3(rotation.eulerAngles.x + 90, 0, rotation.eulerAngles.z);
            scale = new Vector3(Convert.ToSingle(matrix[0]), Convert.ToSingle(matrix[5]), Convert.ToSingle(matrix[10]));   
    }

This works correctly when a threeJS object has no rotation. When it has some rotation, the scale and rotation are not has expected.

If someone has some knowledge about how ThreeJS matrix are working, I'll be glad to have some insights to have it convert to Unity transform.

(note: I can't modify the input from ThreeJS).

EDIT 1 :

    private void GetTransformFromMatrix(double[] matrixT, out Vector3 position, out Quaternion rotation, out Vector3 scale)
    {
        Vector4 row1 = new Vector4(Convert.ToSingle(matrixT[0]), Convert.ToSingle(matrixT[1]), Convert.ToSingle(matrixT[2]), Convert.ToSingle(matrixT[3]));
        Vector4 row2 = new Vector4(Convert.ToSingle(matrixT[4]), Convert.ToSingle(matrixT[5]), Convert.ToSingle(matrixT[6]), Convert.ToSingle(matrixT[7]));
        Vector4 row3 = new Vector4(Convert.ToSingle(matrixT[8]), Convert.ToSingle(matrixT[9]), Convert.ToSingle(matrixT[10]), Convert.ToSingle(matrixT[11]));
        Vector4 row4 = new Vector4(Convert.ToSingle(matrixT[12]), Convert.ToSingle(matrixT[13]), Convert.ToSingle(matrixT[14]), Convert.ToSingle(matrixT[15]));
        Matrix4x4 matrix = new Matrix4x4(row1, row2, row3, row4);

        position = matrix.ExtractPosition();
        rotation = matrix.ExtractRotation();
        scale = matrix.ExtractScale();
    }

Thanks to @flatworldstudio I've managed to get the scale right ; yet the rotation is not quite right , see here :

enter image description here

I'm looking at Unity and ThreeJS coordinate system to understand how the matrix has to be transformed.

EDIT 2 :

    private void GetTransformFromMatrix(double[] matrixT, out Vector3 position, out Quaternion rotation, out Vector3 scale)
    {
        Vector4 row1 = new Vector4(Convert.ToSingle(matrixT[0]), Convert.ToSingle(matrixT[1]), Convert.ToSingle(matrixT[2]), Convert.ToSingle(matrixT[3]));
        Vector4 row2 = new Vector4(Convert.ToSingle(matrixT[4]), Convert.ToSingle(matrixT[5]), Convert.ToSingle(matrixT[6]), Convert.ToSingle(matrixT[7]));
        Vector4 row3 = new Vector4(Convert.ToSingle(matrixT[8]), Convert.ToSingle(matrixT[9]), Convert.ToSingle(matrixT[10]), Convert.ToSingle(matrixT[11]));
        Vector4 row4 = new Vector4(Convert.ToSingle(matrixT[12]), Convert.ToSingle(matrixT[13]), Convert.ToSingle(matrixT[14]), Convert.ToSingle(matrixT[15]));
        Matrix4x4 matrix = new Matrix4x4(row1, row2, row3, row4);
        Matrix4x4 m = Matrix4x4.TRS(new Vector3(), Quaternion.identity, new Vector3(-1, 1, 1));
        matrix = m * matrix;

        position = matrix.ExtractPosition();
        rotation = matrix.ExtractRotation();
        scale = matrix.ExtractScale();
    }

Has done the trick for now ; will close the question with more tests on more complex scenes.

  • The "issue" is simply that ThreeJs has a right handed coordinate system (x=right, y=up, z=towards you) while Units has a left handed system (x=right, y=up, z=away from you) – derHugo Mar 04 '21 at 17:13

1 Answers1

-1

Have a look at this for extracting pos/rot/scl from a matrix4 in unity. https://forum.unity.com/threads/how-to-assign-matrix4x4-to-transform.121966/

Threejs and unity both have a matrix4 object, both are (internally) column major, so they should match if you copy over the values. https://docs.unity3d.com/ScriptReference/Matrix4x4.html https://threejs.org/docs/#api/en/math/Matrix4

From your code i'm not sure if you're assuming row or column major.

  • Thanks flatworldstudio ! I've edit my initial question using your ressources. Still have to figure out a mirror problem, probably coming from different coordinates systems ! – Alexis Delforges Mar 04 '21 at 14:06