- Home /
fluent animation from orthographic to perspective projection
Unity Editor has this neat little feature to switch between orthographic and perspective projection with a fluent, natural animation (by clicking on the axis of the viewport cube).
How can I implement this effect in a custom application?
Answer by Roland1234 · Nov 25, 2013 at 09:01 PM
Even though the question has been asked before and given an answer, I thought I'd post a solution anyways (apologies if that's against guidelines, I saw nothing against it in the FAQ).
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class CameraProjectionChange : MonoBehaviour
{
public float ProjectionChangeTime = 0.5f;
public bool ChangeProjection = false;
private bool _changing = false;
private float _currentT = 0.0f;
private void Update()
{
if(_changing)
{
ChangeProjection = false;
}
else if(ChangeProjection)
{
_changing = true;
_currentT = 0.0f;
}
}
private void LateUpdate()
{
if(!_changing)
{
return;
}
var currentlyOrthographic = camera.orthographic;
Matrix4x4 orthoMat, persMat;
if(currentlyOrthographic)
{
orthoMat = camera.projectionMatrix;
camera.orthographic = false;
camera.ResetProjectionMatrix();
persMat = camera.projectionMatrix;
}
else
{
persMat = camera.projectionMatrix;
camera.orthographic = true;
camera.ResetProjectionMatrix();
orthoMat = camera.projectionMatrix;
}
camera.orthographic = currentlyOrthographic;
_currentT += (Time.deltaTime / ProjectionChangeTime);
if(_currentT < 1.0f)
{
if(currentlyOrthographic)
{
camera.projectionMatrix = MatrixLerp(orthoMat, persMat, _currentT * _currentT);
}
else
{
camera.projectionMatrix = MatrixLerp(persMat, orthoMat, Mathf.Sqrt(_currentT));
}
}
else
{
_changing = false;
camera.orthographic = !currentlyOrthographic;
camera.ResetProjectionMatrix();
}
}
private Matrix4x4 MatrixLerp(Matrix4x4 from, Matrix4x4 to, float t)
{
t = Mathf.Clamp(t, 0.0f, 1.0f);
var newMatrix = new Matrix4x4();
newMatrix.SetRow(0, Vector4.Lerp(from.GetRow(0), to.GetRow(0), t));
newMatrix.SetRow(1, Vector4.Lerp(from.GetRow(1), to.GetRow(1), t));
newMatrix.SetRow(2, Vector4.Lerp(from.GetRow(2), to.GetRow(2), t));
newMatrix.SetRow(3, Vector4.Lerp(from.GetRow(3), to.GetRow(3), t));
return newMatrix;
}
}
Surprisingly, linear interpolation between matrices seems to do the trick.
I see that you square the t parameter when you transit to perspective, and you squareroot it when you transit to orthographic, but this does not seem to be the full truth as it doesn't yield a smooth, linear transition to me (even though better than t is used directly) - can you mathematically reason about this? Also, how to properly change/animate the position of the camera? Since the position does not matter for orthographic projection, but matters for perspective projection, the current code gives only a nice transition if the camera distance to the object is in a certain relation to the orthographicSize of the orthographic camera
can you mathematically reason about this?
$$anonymous$$athematically, not quite - but geometrically I believe the effect is due to things that are further away from the camera beco$$anonymous$$g more greatly distorted as the view frustum goes from pyramid shape to box than things that are closer.
After spending some time analyzing the editor camera I had to conclude that their approach is fundamentally different - you are absolutely correct in noticing that the camera's position is changing. The editor camera doesn't interpolate the projection matrices, it fakes an orthogonal projection by using a very small FOV from a great distance, and transitions the change by increasing the FOV while decreasing the distance about a target position (which is the origin by default and set to an object's position when you double-click it in the hierarchy pane).
With that in $$anonymous$$d I've attached an implementation which looks to effectively mimic the editor functionality. Just be sure to change the file extension to .cs.
Setting a focus point is optional; the script will default to the origin if none is set. Let me know if this is what you were looking for!
Thanks for posting this solution! Sorry to necro, but how does the ProjectionChangeTime float work? It doesn't seem to correspond directly to seconds. For example, this is what I get when I set ProjectionChangeTime to 2, yet it looks like the transition takes maybe 0.5 seconds: https://gfycat.com/HospitableDisastrousAardwolf
Answer by iwaldrop · Nov 25, 2013 at 07:56 PM
This question has already been answered, here:
http://answers.unity3d.com/questions/58306/transition-a-camera-from-ortographic-to-perspectiv.html