Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Fun with projection matrices

Discussion in 'Scripting' started by Kragh, Apr 8, 2020.

  1. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    EDIT: So I tried to implement the same functionality, but with a double precision matrix/vector library (XnaGeometry is just perfect, have used it for many things in the past!!!), and now it works great. So even though I felt the small error on the far plane calculation seemed too large for a floating point precision offset alone, it IS because of that.
    _____________________
    So I am trying to understand the projection matrix in depth (Or as close as I can get), because I need to be able to do all the built-in functionality of a camera (Like worldToScreen, screenToWorld and so on) without having an actual camera.
    But I do have the same parameters to built my matrices from: fov, near, far, translation and so on.

    So far I have been able to calculate a projection matrix like so:
    Code (CSharp):
    1. Matrix4x4 ProjectionMatrix(float fovRadians, float nearClip, float farClip, float aspect)
    2.     {
    3.         Matrix4x4 projectionMatrix = new Matrix4x4();
    4.  
    5.         Vector4 c0 = new Vector4();
    6.         Vector4 c1 = new Vector4();
    7.         Vector4 c2 = new Vector4();
    8.         Vector4 c3 = new Vector4();
    9.         c0.x = 1f / (aspect * Mathf.Tan(fovRadians / 2));
    10.         c1.y = 1f / Mathf.Tan(fovRadians / 2);
    11.         c2.z = (nearClip + farClip) / (nearClip - farClip);
    12.         c2.w = -1;
    13.         c3.z = (2 * nearClip * farClip) / (nearClip - farClip);
    14.  
    15.         projectionMatrix.SetColumn(0, c0);
    16.         projectionMatrix.SetColumn(1, c1);
    17.         projectionMatrix.SetColumn(2, c2);
    18.         projectionMatrix.SetColumn(3, c3);
    19.         return projectionMatrix;
    20.     }
    Seems to create a matrix that matches unity's projection matrix, given the same parameters (They come out as equal, when compared by ==)

    Then I made a function that tried to calculate the near and far planes FROM a projection matrix:
    Code (CSharp):
    1. void NearFarFromProjection (Matrix4x4 projectionMatrix, out float near, out float far)
    2.     {
    3.         near = (2.0f * projectionMatrix[2,3]) / (2.0f * projectionMatrix[2, 2] - 2.0f);
    4.         far = ((projectionMatrix[2, 2] - 1.0f) * near) / (projectionMatrix[2, 2] + 1.0f);
    5.     }
    And it seems to work. Almost. The "near" comes out perfectly, but the "far" plane is off by more than rounding errors or precision of floating point arithmetic would suggest.

    If I use the first function to build a projection, and send in 0.3 and 1000 as near/far, and then try and calculate them again from the matrix I just created, the values are now: 0.3 and 999.9355

    It seems close enough that I have something done right in that code. But also strangely too far off on the far plane. And I can't seem to figure out why. It is not like a lot of floats are continuously done math on, to produce rounding or precision errors.

    Both of these functions have been made byt picking and choosing from various sources out there, so I don't fully understand their nature yet.

    Anybody can point me to the precise place where this is either slightly wrong, or where some rounding errors might creep in? Is this close enough? Should I just move on?
     
    Last edited: Apr 9, 2020
    Olmi likes this.
  2. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    Solved: WAS due to floating point precision. Double precision in both matrices and vectors fixed it...