Search Unity

Difference between unity_WorldToObject and the inverse of UNITY_MATRIX_VP

Discussion in 'Shaders' started by Isomania, Jul 2, 2022.

  1. Isomania

    Isomania

    Joined:
    Jan 28, 2021
    Posts:
    16
    Hi!

    One day, just from frustration I tried replacing my inverse(UNITY_MATRIX_VP) with other matrices and I noticed that unity_WorldToObject and inverse(UNITY_MATRIX_VP) both worked equally for my use case with involves orthographic cameras where I'am transforming a vertice from clip back to world space.

    So I want to know the difference between unity_WorldToObject and the inverse of UNITY_MATRIX_VP.

    If it comes out that replacing the inverse of UNITY_MATRIX_VP to unity_WorldToObject for my specific use case, shouldn't be done. Then please answer why/what could happen. And preferably a replacement for inverse(UNITY_MATRIX_VP), since I can not find it in Unity Built-in shader variables and I have to calculate it for each vertex (which all gets really expensive) because I have multiple cameras and I can not pass it to the shader using script, or atleast I do not think I can.
     
    Swifter1243 likes this.
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    UNITY_MATRIX_VP
    is the world to clip space matrix, also known as the “View Projection matrix”. The inverse would be the clip space to world space transform.

    unity_WorldToObject
    is the world to object space matrix, also known as the “inverse Model matrix”.

    If they both happen to work for your use case it means your orthographic camera’s projection just happens to match your object’s object space. In any other setup, they should not match.

    And you are correct that there’s no inverse VP matrix passed to shaders by default. You can calculate it in c# and set it on the materials or set it as a shader global. There is a
    unity_CameraInvProjection
    matrix, but this doesn’t match the inverse of the
    UNITY_MATRIX_P
    in most cases, let alone the inverse
    UNITY_MATRIX_VP
    . The
    unity_CameraProjection
    matrix and
    UNITY_MATRIX_P
    represent the same projection matrix, but the “Camera” ones alway match the OpenGL matrix as exists on the main camera component’s matrices as they appear in c#, and the
    UNITY_MATRIX_P
    is the projection matrix for the current graphics API, for the currently rendered view. Since you’re not always rendering the main camera’s view, and likely are not using OpenGL unless you’re targeting old Android devices, they don’t match.
     
    Isomania likes this.
  3. Isomania

    Isomania

    Joined:
    Jan 28, 2021
    Posts:
    16
    Thanks for the answer!

    Theres just two small things:

    As I said I use multiple cameras to render the scene each with their own VP matrix. So whats best practice to expose multiple matrices through code? Should I expose one global matrix for each camera and do if statements in the shader to what camera is beeing rendered?
    EDIT:
    omg i just overwrite the same property id on precull...

    I also have to ask, since there’s no inverse VP matrix passed to shaders by default, is it bad shader practice/structure to use it? If I per se have to snap a objects center to my cameras pixelgrid, I see no way of doing that that doesn't result in me having to have access to the inverse VP matrix. No?
     
  4. Isomania

    Isomania

    Joined:
    Jan 28, 2021
    Posts:
    16
    For anyone whos looking for code:

    This should be added to one script on all your camera gameObjects:

    Code (CSharp):
    1. /// <summary>
    2. /// Before culling the environment:
    3. /// Overwrite global UNITY_MATRIX_I_VP shader matrix to represent this camera.
    4. /// </summary>
    5. private void OnPreCull()
    6. {
    7.     Shader.SetGlobalMatrix("UNITY_MATRIX_I_VP", mCamera.MATRIX_I_VP());
    8. }
    And this is the camera extension methods I've created. Should be on its own seperate script:

    Code (CSharp):
    1. #region unity_camera_extensions
    2. public static class UnityCameraExtensions
    3. {
    4.     /// <summary>
    5.     /// View matrix of camera
    6.     /// </summary>
    7.     public static Matrix4x4 MATRIX_V(this Camera camera)
    8.     {
    9.         Matrix4x4 viewMat = camera.worldToCameraMatrix;
    10.         return viewMat;
    11.     }
    12.  
    13.     /// <summary>
    14.     /// Projection matrix of camera
    15.     /// </summary>
    16.     public static Matrix4x4 MATRIX_P(this Camera camera)
    17.     {
    18.         Matrix4x4 projMat = GL.GetGPUProjectionMatrix(camera.projectionMatrix, true);
    19.         return projMat;
    20.     }
    21.  
    22.     /// <summary>
    23.     /// View-projection matrix of camera (MATRIX_P * MATRIX_V)
    24.     /// </summary>
    25.     public static Matrix4x4 MATRIX_VP(this Camera camera)
    26.     {
    27.         return (camera.MATRIX_P() * camera.MATRIX_V());
    28.     }
    29.  
    30.     /// <summary>
    31.     /// Inverse view-projection matrix of camera (MATRIX_P * MATRIX_V).inverse
    32.     /// </summary>
    33.     public static Matrix4x4 MATRIX_I_VP(this Camera camera)
    34.     {
    35.         return (camera.MATRIX_VP()).inverse;
    36.     }
    37. }
    38. #endregion