各种Camera,总有一款适合你(二)
生活随笔
收集整理的這篇文章主要介紹了
各种Camera,总有一款适合你(二)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在實際的項目開發中,一般需要程序抽象出一些在幾何意義上有明確意義的參數,這樣方便策劃或美術在自己的機器上進行調試。
下面是一個可變參的地下城攝像機的簡單實現:
// 第三人稱攝像機,平移和旋轉會同時進行平滑 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; // 平滑時間,默認為1spublic float ScrollWheelSpeed = 1000f; // 中軸調整速度public Vector3 TargetOffset = Vector3.zero; // 目標偏移量private Vector3 Velocity = Vector3.zero; // 平滑初速度private Vector3 Offset = Vector3.zero; // 根據上面三個變量計算出private const float MinDistance = 5f; // 鏡頭最近距離private const float MaxDistance = 100f; // 鏡頭最遠距離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;}}可以看到抽象出的控制參數主要包括:攝像機分別繞X軸和Y軸的旋轉、攝像機距離角色的距離、以及用來控制平滑時間的參數。
注意,上面這段代碼的實現中,position和rotation是同時進行平滑的,下面來看另外一種實現:
using UnityEngine; using System.Collections;[ExecuteInEditMode] public class MyDungeonCamera : MonoBehaviour {/// [攝像機控制參數]public GameObject Target = null;public float RotateX = 0f; // pitch 俯仰public float RotateY = 0f; // yaw 偏航public float Distance = 10f; // 攝像機遠近public float MoveSmoothTime = 0.3f; // 位置平滑時間,默認為1spublic float RotateSmoothTime = 0.3f; // 旋轉平滑時間public float ScrollWheelSpeed = 1000f; // 中軸調整速度public Vector3 TargetOffset = Vector3.zero; // 目標偏移量private Vector3 Velocity = Vector3.zero; // 平滑初速度private Vector3 Offset = Vector3.zero; // 根據上面三個變量計算出private const float MinDistance = 5f; // 鏡頭最近距離private const float MaxDistance = 100f; // 鏡頭最遠距離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);// 旋轉采用球形插值tmpRotation = Quaternion.Slerp(tmpRotation, wantedRotation, Time.deltaTime * RotateDamping);}private void UpdatePosition(){// 如果有旋轉插值,則位置根據旋轉變換;否則,位置自己進行插值過渡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;}}這個實現中,有幾點需要注意的:
(1)rotation使用四元素球形插值,這樣保證每次旋轉的角速度是恒定的,不過兩次旋轉各自的角速度不相等,這里可以改進;
(2)position使用Vector3.SmoothDamp進行平滑阻尼過渡效果會比較好;
(3)浮點數相等判斷,不要直接用等號喲;
(4)當同時有rotation和position時,以rotation為主;
(5)是否需要旋轉的判斷,只有需要的時候才走旋轉邏輯,這樣可以減輕Update的壓力。
攝像機振動腳本:
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;}}?
轉載于:https://www.cnblogs.com/sifenkesi/p/3994594.html
總結
以上是生活随笔為你收集整理的各种Camera,总有一款适合你(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C语言笔记初级篇】第二章:分支与循环
- 下一篇: (软件工程复习核心重点)第三章需求分析-