Unity-Technologies / Unity.Mathematics

The C# math library used in Unity providing vector types and math functions with a shader like syntax
Other
1.38k stars 156 forks source link

float4x4.PerspectiveOffCenter(): possible logic flaw? #247

Open niguiecandy opened 6 months ago

niguiecandy commented 6 months ago

The Unity.Mathematics implementation of PerspectiveOffCenter() Link

public static float4x4 PerspectiveOffCenter(float left, float right, float bottom, float top, float near, float far)
{
    float rcpdz = 1.0f / (near - far);
    float rcpWidth = 1.0f / (right - left);
    float rcpHeight = 1.0f / (top - bottom);

    return float4x4(
        2.0f * near * rcpWidth,     0.0f,                       (left + right) * rcpWidth,     0.0f,
        0.0f,                       2.0f * near * rcpHeight,    (bottom + top) * rcpHeight,    0.0f,
        0.0f,                       0.0f,                        **(far + near) * rcpdz**,          **2.0f * near * far * rcpdz**,
        0.0f,                       0.0f,                       -1.0f,                          0.0f
        );
}

differs from the .NET System.Numerics.Matrix4x4 implementation:

public static Matrix4x4 CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance)
{
    if (nearPlaneDistance <= 0.0f)
        throw new ArgumentOutOfRangeException("nearPlaneDistance");

    if (farPlaneDistance <= 0.0f)
        throw new ArgumentOutOfRangeException("farPlaneDistance");

    if (nearPlaneDistance >= farPlaneDistance)
        throw new ArgumentOutOfRangeException("nearPlaneDistance");

    Matrix4x4 result;

    result.M11 = 2.0f * nearPlaneDistance / (right - left);
    result.M12 = result.M13 = result.M14 = 0.0f;

    result.M22 = 2.0f * nearPlaneDistance / (top - bottom);
    result.M21 = result.M23 = result.M24 = 0.0f;

    result.M31 = (left + right) / (right - left);
    result.M32 = (top + bottom) / (top - bottom);
    // below is different
    **result.M33 = farPlaneDistance / (nearPlaneDistance - farPlaneDistance);**
    result.M34 = -1.0f;
    // below is different
    **result.M43 = nearPlaneDistance * farPlaneDistance / (nearPlaneDistance - farPlaneDistance);**
    result.M41 = result.M42 = result.M44 = 0.0f;

    return result;
}

In Unity M33 is: (far + near) * rcpdz while System M33 is: result.M33 = farPlaneDistance / (nearPlaneDistance - farPlaneDistance);

In Unity M34 is: 2.0f * near * far * rcpdz while System M43 is: result.M43 = nearPlaneDistance * farPlaneDistance / (nearPlaneDistance - farPlaneDistance);

Note that both matrices are transposed to each other; System Matrix can be thought of as rotating the coordinate system itself while Unity Matrix rotates the given vector.