Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Understanding Camera Matrix Lerps

Discussion in 'Scripting' started by _eternal, Oct 26, 2016.

  1. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    301
    I'm trying to smoothly transition my camera from orthographic to perspective at runtime. I found this old script that seems to do the trick: https://community.unity.com/t5/Scri...erspective-and-orthographic-modes/td-p/279075

    In particular, here's what the lerp method looks like:

    Code (CSharp):
    1. public static Matrix4x4 MatrixLerp(Matrix4x4 from, Matrix4x4 to, float time)
    2. {
    3.     Matrix4x4 ret = new Matrix4x4();
    4.     for (int i = 0; i < 16; i++)
    5.         ret[i] = Mathf.Lerp(from[i], to[i], time);
    6.     return ret;
    7. }
    The method works, but the effect isn't very smooth. It appears to ease in/out very quickly, depending on whether I'm switching from ortho to perspective or vice versa. Here's an example: https://gfycat.com/UniformOddImperialeagle

    Now, I'm guessing that this is expected behavior, since I don't see anything about easing in the MatrixLerp method. But is there a way to make this effect more linear, or at least slow it down a bit? I'm not too clear on how projection matrices work in the first place, so it's difficult to troubleshoot.
     
  2. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Well to answer your question you have to understand what a projection Matrix is doing. Its taking a world XYZ and converting it to Normalized Device Coordinates [NDC]. NDC is usually defined from -1 to + 1. So if we are taking the following:
    • X Axis in the range from [r,l] to [-1,1] r=right most coord, l = left most coord
    • Y Axis in the range from [b,t] to [-1,1] b= bot most coord, t = top most coord
    • Z Axis in the range from [n,f] to [-1,1] n = near clip plane (normally 0.3f) and f = far clip (normally 1000)
    Assuming the viewing area is symmetric r = -l and b = -t (the origin is in the middle of our volume)
    n/r 0 0 0
    0 n/t 0 0
    0 0 -(f+n)/(f-n) -2fn/(f-n)
    0 0 -1 0

    Othographic Cameras look like this:
    1/r 0 0 0
    0 1/t 0 0
    0 0 -2/(f-n) -(f+n)/(f-n)
    0 0 0 1

    Here is a link to how to derive those matrices:
    Its for OpenGL but its the same for Unity in general.
    http://www.songho.ca/opengl/gl_projectionmatrix.html

    I did some playing around and it feels like going from projection to ortho the first half of the lerp doesn't move very much and the last half moves very quickly. You can make a modified time so the first half the time frame covers the first 2/3 of the lerp, while the last 1/2 of the time covers the last 1/3.. effectively speeding up the first part and slowing down the second.

    Code (CSharp):
    1. public static Matrix4x4 MatrixLerp(Matrix4x4 from, Matrix4x4 to, float time, float firstHalfAdjust=1.0f)
    2.     {
    3.         float secondHalfAdjust = 2.0f - firstHalfAdjust;
    4.         if (time <= .5)
    5.             time = time * firstHalfAdjust;
    6.         else
    7.             time = 0.5f * (firstHalfAdjust) + (time - .5f) * (secondHalfAdjust);
    8.      
    9.        
    10.         Matrix4x4 ret = new Matrix4x4();
    11.         for (int i = 0; i < 16; i++)
    12.             ret[i] = Mathf.Lerp(from[i], to[i], time);
    13.         return ret;
    14.     }
    So to lerp from proj to Ortho you'd set firstHalfAdjust somewhere around 1.5->1.7f. Now you'd need to flip this going from Ortho to Proj by setting it to .5->.3
     
    _eternal likes this.
  3. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    301
    Awesome, it's still a little uneven but I see where you're coming from. I'll play with the values a bit. Thanks!