各种Camera,总有一款适合你(二)
在實(shí)際的項(xiàng)目開發(fā)中,一般需要程序抽象出一些在幾何意義上有明確意義的參數(shù),這樣方便策劃或美術(shù)在自己的機(jī)器上進(jìn)行調(diào)試。
下面是一個(gè)可變參的地下城攝像機(jī)的簡單實(shí)現(xiàn):
// 第三人稱攝像機(jī),平移和旋轉(zhuǎn)會(huì)同時(shí)進(jìn)行平滑 public class ThirdPersonalCamera : MonoBehaviour {/// Camera Control Paramspublic GameObject Target = null;public float Distance = 10f;public float RotateX = 0f; // pitch 俯仰public float RotateY = 0f; // yaw 偏航public float SmoothTime = 0.01f; // 平滑時(shí)間,默認(rèn)為1spublic float ScrollWheelSpeed = 1000f; // 中軸調(diào)整速度public Vector3 TargetOffset = Vector3.zero; // 目標(biāo)偏移量private Vector3 Velocity = Vector3.zero; // 平滑初速度private Vector3 Offset = Vector3.zero; // 根據(jù)上面三個(gè)變量計(jì)算出private const float MinDistance = 5f; // 鏡頭最近距離private const float MaxDistance = 100f; // 鏡頭最遠(yuǎn)距離void Start(){if (Target == null) return;}public void Shake(){StartCoroutine("ShakeCoroutine");}void LateUpdate(){if (Target == null) return;UpdateDistance();float radX = Mathf.Deg2Rad * RotateX;float radY = Mathf.Deg2Rad * RotateY;Offset.x = Distance * Mathf.Cos(radX) * Mathf.Cos(radY);Offset.z = Distance * Mathf.Cos(radX) * Mathf.Sin(radY);Offset.y = Distance * Mathf.Sin(radX);Vector3 targetPos = Target.transform.position + Offset + TargetOffset;transform.position = Vector3.SmoothDamp(transform.position, targetPos, ref Velocity, SmoothTime);transform.LookAt(Target.transform.position + TargetOffset);}private void UpdateDistance(){float horizontal = Input.GetAxis("Mouse ScrollWheel") * ScrollWheelSpeed * Time.deltaTime;Distance -= horizontal;}}可以看到抽象出的控制參數(shù)主要包括:攝像機(jī)分別繞X軸和Y軸的旋轉(zhuǎn)、攝像機(jī)距離角色的距離、以及用來控制平滑時(shí)間的參數(shù)。
注意,上面這段代碼的實(shí)現(xiàn)中,position和rotation是同時(shí)進(jìn)行平滑的,下面來看另外一種實(shí)現(xiàn):
using UnityEngine; using System.Collections;[ExecuteInEditMode] public class MyDungeonCamera : MonoBehaviour {/// [攝像機(jī)控制參數(shù)]public GameObject Target = null;public float RotateX = 0f; // pitch 俯仰public float RotateY = 0f; // yaw 偏航public float Distance = 10f; // 攝像機(jī)遠(yuǎn)近public float MoveSmoothTime = 0.3f; // 位置平滑時(shí)間,默認(rèn)為1spublic float RotateSmoothTime = 0.3f; // 旋轉(zhuǎn)平滑時(shí)間public float ScrollWheelSpeed = 1000f; // 中軸調(diào)整速度public Vector3 TargetOffset = Vector3.zero; // 目標(biāo)偏移量private Vector3 Velocity = Vector3.zero; // 平滑初速度private Vector3 Offset = Vector3.zero; // 根據(jù)上面三個(gè)變量計(jì)算出private const float MinDistance = 5f; // 鏡頭最近距離private const float MaxDistance = 100f; // 鏡頭最遠(yuǎn)距離private Quaternion tmpRotation = Quaternion.identity;private Vector3 tmpPosition = Vector3.zero;private float RotateDamping{get{if (RotateSmoothTime <= 0f) RotateSmoothTime = 0.001f;return 1f / RotateSmoothTime;}}void LateUpdate(){if (Target == null) return;tmpRotation = transform.rotation;tmpPosition = transform.position;UpdateDistance();UpdateRotation();UpdatePosition();transform.rotation = tmpRotation;transform.position = tmpPosition;}private void UpdateRotation(){if (!NeedRotate()) return;Quaternion wantedRotation = Quaternion.Euler(RotateX, RotateY, 0f);// 旋轉(zhuǎn)采用球形插值tmpRotation = Quaternion.Slerp(tmpRotation, wantedRotation, Time.deltaTime * RotateDamping);}private void UpdatePosition(){// 如果有旋轉(zhuǎn)插值,則位置根據(jù)旋轉(zhuǎn)變換;否則,位置自己進(jìn)行插值過渡if (!NeedRotate()){Offset = Quaternion.Euler(RotateX, RotateY, 0f) * Vector3.forward * Distance;Vector3 wantedPos = Target.transform.position - Offset + TargetOffset;// 位置采用平滑阻尼過渡tmpPosition = Vector3.SmoothDamp(tmpPosition, wantedPos, ref Velocity, MoveSmoothTime);}else{Offset = tmpRotation * Vector3.forward * Distance;tmpPosition = Target.transform.position - Offset + TargetOffset;}}private void UpdateDistance(){float horizontal = Input.GetAxis("Mouse ScrollWheel") * ScrollWheelSpeed * Time.deltaTime;Distance -= horizontal;Distance = Mathf.Clamp(Distance, MinDistance, MaxDistance);}private bool NeedRotate(){Vector3 eulerAngles = transform.rotation.eulerAngles;return !(FloatEqual(eulerAngles.x, RotateX) && FloatEqual(eulerAngles.y, RotateY));}public static bool FloatEqual(float value1, float value2){float ret = value1 - value2;return ret > -0.0005f && ret < 0.0005f;}}這個(gè)實(shí)現(xiàn)中,有幾點(diǎn)需要注意的:
(1)rotation使用四元素球形插值,這樣保證每次旋轉(zhuǎn)的角速度是恒定的,不過兩次旋轉(zhuǎn)各自的角速度不相等,這里可以改進(jìn);
(2)position使用Vector3.SmoothDamp進(jìn)行平滑阻尼過渡效果會(huì)比較好;
(3)浮點(diǎn)數(shù)相等判斷,不要直接用等號喲;
(4)當(dāng)同時(shí)有rotation和position時(shí),以rotation為主;
(5)是否需要旋轉(zhuǎn)的判斷,只有需要的時(shí)候才走旋轉(zhuǎn)邏輯,這樣可以減輕Update的壓力。
攝像機(jī)振動(dòng)腳本:
public class ShakeCamera : MonoBehaviour {public float ShakeTime = 1f;public float ShakeStrength = 0.2f;private Vector3 ShakeOffset = Vector3.zero;private Vector3 preShakeOffset = Vector3.zero;void LateUpdate(){transform.position = transform.position - preShakeOffset + ShakeOffset;}public void Shake(){StopCoroutine("ShakeCoroutine");StartCoroutine("ShakeCoroutine");}public void Shake(float time){ShakeTime = time;Shake();}IEnumerator ShakeCoroutine(){float endTime = Time.time + ShakeTime;while (Time.time < endTime){ShakeOffset = Random.insideUnitSphere * ShakeStrength;yield return null;}ShakeOffset = Vector3.zero;}}?
轉(zhuǎn)載于:https://www.cnblogs.com/sifenkesi/p/3994594.html
總結(jié)
以上是生活随笔為你收集整理的各种Camera,总有一款适合你(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C语言笔记初级篇】第二章:分支与循环
- 下一篇: (软件工程复习核心重点)第三章需求分析-