在Unity3D中如何让摄像机进行平滑的透视(perspective)和正视(orthographic)角度变换(就像编辑器中点击Gizmos一样的效果)

在Unity3D中如何让摄像机进行平滑的透视(perspective)和正视(orthographic)角度变换(就像编辑器中点击Gizmos一样的效果)

How to make a smooth  animation from orthographic to perspective projection with camera in Unity3D


U3D在Scene场景中编译器里有个XYX左边的Gizmos,点击中间Cube 就可以切换观看GameObject的透视(perspective)和正视(orthographic)角度,如图:

那么,如果我想在代码里动态实现,如何写呢?


(并没有想象的那么简单:在代码中调用camera.Projection的俩个枚举等等。这里面牵扯到一些Matrix矩阵之类的,大家往下看)

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?

1、首先我设置如下场景,透过按钮点击Gizmos可以看出透视与正视的不同来:



透视(上)



大家注意cube的顶面的梯形上小下大与上大下小的区别!


2、最终结果我么我们期望能用一个按钮来控制俩种状态的切换。整体代码如下:BackupCameraProjectionChange.cs

using UnityEngine;
using System.Collections;

public class BackupCameraProjectionChange: MonoBehaviour
{

	 /// <summary>
	 /// 相机透视改变是否触发(调用只需把此值改为true)
	 /// </summary>
     public bool ChangeProjection = false; 
     private bool _changing = false;
     public float ProjectionChangeTime = 0.5f;
     private float _currentT = 0.0f;
 
     private void Update()
     {///检测,避免变换过程中发生混乱
         if(_changing)
         {
             ChangeProjection = false;
         }
         else if(ChangeProjection)
         {
             _changing = true;
             _currentT = 0.0f;
         }
     }
  /// <summary>
  /// Unity3D中Update和Lateupdate的区别。Lateupdate和Update每一祯都被执行,但是执行顺序不一样,先执行Updatee然后执行lateUpdate。
 ///如果你有两个脚本JS1、JS2,两个脚本中都有Update()函数, 在JS1中有 lateUpdate ,JS2中没有。那么 lateUpdate 函数会等待JS1、JS2两个脚本的Update()函数 都执行完后才执行。
 /// </summary>
     private void LateUpdate()
     {
         if(!_changing)
         {
             return;
         }
         //将当前的 是否正视图值 赋值给currentlyOrthographic变量
         bool currentlyOrthographic = Camera.main.orthographic;
         //定义变量存放当前摄像机的透视和正视矩阵信息;
         Matrix4x4 orthoMat, persMat;
         if(currentlyOrthographic)//如果当前摄像机为正视状态
         {
             orthoMat = Camera.main.projectionMatrix;
 
             Camera.main.orthographic = false;
             Camera.main.ResetProjectionMatrix();
             persMat = Camera.main.projectionMatrix;
         } else//否则当前摄像机为透视状态
         {
             persMat = Camera.main.projectionMatrix;
 
             Camera.main.orthographic = true;
             Camera.main.ResetProjectionMatrix();
             orthoMat = Camera.main.projectionMatrix;
         }
         Camera.main.orthographic = currentlyOrthographic;
 
         _currentT += (Time.deltaTime / ProjectionChangeTime);
         if(_currentT < 1.0f)
         {
             if(currentlyOrthographic)
             {
                 Camera.main.projectionMatrix = MatrixLerp(orthoMat, persMat, _currentT * _currentT);
             }
             else
             {
                 Camera.main.projectionMatrix = MatrixLerp(persMat, orthoMat, Mathf.Sqrt(_currentT));
             }
         }
         else
         {
             _changing = false;
             Camera.main.orthographic = !currentlyOrthographic;
             Camera.main.ResetProjectionMatrix();
         }
     }
 
     private Matrix4x4 MatrixLerp(Matrix4x4 from, Matrix4x4 to, float t)
     {
         t = Mathf.Clamp(t, 0.0f, 1.0f);
         Matrix4x4 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;
     }
 
    void OnGUI()
    {
        GUILayout.Label("New Camera.main.projectionMatrix:\n" + Camera.main.projectionMatrix.ToString());
        if ( GUILayout.Button("更改CameraProjection") ) {
            ChangeProjection = true;
        }
    }
}


 


把脚本附着在游戏物体 MainCamera上,
无需更改数值;直接运行如图:




至此,方法讲解完毕,大家多多揣摩。多多提出意见和建议。
喜欢音乐,热爱生活,哈喽,大家好,我是阿祥。



亲爱的,有个省钱利器我必须告诉你,能省很多Money! 点击下方文字即可打开

淘宝购物返现网


亲爱的,有个省钱利器我必须告诉你,能省很多Money! 点击下方文字即可打开

淘宝购物返现网

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LuckyDog阿祥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值