float4x4.TRS does TSR instead

The float4x4.TRS method applies scale on top of rotation instead of the other way around. This makes no difference for uniform scaling but makes a big difference for non-uniform scaling.

 public static float4x4 TRS(float3 translation, quaternion rotation, float3 scale)
        {
            float3x3 r = float3x3(rotation);
            return float4x4(  float4(r.c0 * scale.x, 0.0f),
                              float4(r.c1 * scale.y, 0.0f),
                              float4(r.c2 * scale.z, 0.0f),
                              float4(translation, 1.0f));
        }

The indicated TRS transformation matches Unity’s GO transformation matrix behavior. The actual TSR transformation does not.

My suggestion is to make TRS perform the indicated transformation and add a high-performance variant with a float scale parameter for uniform scaling.

    // Current unexpected behavior.
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static float4x4 TSR (float3 translation, quaternion rotation, float3 scale) {
        float3x3 r = float3x3(rotation);
        return float4x4(float4(r.c0 * scale.x, 0.0f),
        float4(r.c1 * scale.y, 0.0f),
        float4(r.c2 * scale.z, 0.0f),
        float4(translation, 1.0f));
    }

    // Correct expected behavior.
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static float4x4 TRS (float3 translation, quaternion rotation, float3 scale) {
        float3x3 m = mul(Unity.Mathematics.float3x3.Scale(scale), float3x3(rotation));
        return float4x4(float4(m.c0, 0.0f),
        float4(m.c1, 0.0f),
        float4(m.c2, 0.0f),
        float4(translation, 1.0f));
    }

    // Optimized for uniform scale.
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static float4x4 TRS (float3 translation, quaternion rotation, float scale) {
        float3x3 r = float3x3(rotation);
        return float4x4(float4(r.c0 * scale, 0.0f),
        float4(r.c1 * scale, 0.0f),
        float4(r.c2 * scale, 0.0f),
        float4(translation, 1.0f));
    }
8 Likes

Thanks for taking the time to post about this! And for providing a function to fix it.

I’ve been scratching my head wondering what the heck was going on with these AABBs I was trying to TRS inside a job. “Why is the Y size so small!?”, I was saying.

I imagine this is the culprit.