Siccity / GLTFUtility

Simple GLTF importer for Unity
MIT License
996 stars 218 forks source link

Transform matrices in scene hierarchy not interpreted correctly. #163

Open nwessing opened 2 years ago

nwessing commented 2 years ago

I have a stripped down example here where the GTLFUtility does not generate the correct transform for a particular node. Here is the file

gltf_files.zip

Here is how the model should be rendered (screenshot from Windows 3D viewer): Windows3DViewer

Here is how the model is rendered after imported into Unity with GLTFUtility: GltfUtilityUnity

I have tested this in several other GLTF viewers and they all match behavior with Windows 3D Viewer. Babylon.js Babylonjs

Cesium Cesium

Filament Filament

Threejs Threejs

Khronos's GLTF importer interprets the matrix a bit differently than this importer does. https://github.com/KhronosGroup/UnityGLTF/blob/1e003333698be2d6026211c2ee85ddbd25d07b72/UnityGLTF/Assets/UnityGLTF/Runtime/Scripts/Extensions/SchemaExtensions.cs#L171

https://github.com/KhronosGroup/UnityGLTF/blob/1e003333698be2d6026211c2ee85ddbd25d07b72/UnityGLTF/Assets/UnityGLTF/Runtime/Scripts/Extensions/SchemaExtensions.cs#L42

code-monkey-101 commented 2 years ago

I'm surprised, this bug hasn't been fixed yet since it makes the tool basically unusable.

This is how you fix it based on the code that @nwessing posted: Change the ApplyTRS method in GLTFNode.cs to this:

/// <summary> Set local position, rotation and scale </summary>
public void ApplyTRS(Transform transform) {
    /// glTF is a right-handed coordinate system, where the 'right' direction is -X relative to Unity's coordinate system.
    /// glTF matrix: column vectors, column-major storage, +Y up, +Z forward, -X right, right-handed
    /// Unity matrix: column vectors, column-major storage, +Y up, +Z forward, +X right, left-handed
    /// Multiply by a negative X scale to convert handedness
    Vector3 coordinateSpaceConversionScale = new Vector3(-1, 1, 1);
    if (matrix != Matrix4x4.identity)
    {
        Matrix4x4 convert = Matrix4x4.Scale(coordinateSpaceConversionScale);
        Matrix4x4 matrixLH = convert * matrix * convert;

        transform.localPosition = matrixLH.GetColumn(3);

        Vector3 x = matrixLH.GetColumn(0);
        Vector3 y = matrixLH.GetColumn(1);
        Vector3 z = matrixLH.GetColumn(2);
        Vector3 calculatedZ = Vector3.Cross(x, y);
        bool mirrored = Vector3.Dot(calculatedZ, z) < 0.0f;
        transform.localScale = new Vector3(x.magnitude * (mirrored ? -1.0f : 1.0f), y.magnitude, z.magnitude);

        transform.localRotation = Quaternion.LookRotation(matrixLH.GetColumn(2), matrixLH.GetColumn(1));
    }
    else
    {
        transform.localPosition = Vector3.Scale(translation, coordinateSpaceConversionScale);

        Vector3 fromAxisOfRotation = new Vector3(rotation.x, rotation.y, rotation.z);
        Vector3 toAxisOfRotation = -1.0f * Vector3.Scale(fromAxisOfRotation, coordinateSpaceConversionScale);
        transform.localRotation = new Quaternion(toAxisOfRotation.x, toAxisOfRotation.y, toAxisOfRotation.z, rotation.w);

        transform.localScale = scale;
    }
}