嗯…
明明是個很簡單的東西,可是卻一直無法透徹了解
這是書本上的範例,邊打邊複習,順便撐篇數(歐飛)
文章中參雜書本直接的翻譯和我自己的話混合而成,所以可能看起來會怪怪的…
大部分是因為不知道怎樣翻比較順,就自己隨意補上了~
在這個 ThirdPersonCamera 類別裡,你可以創造 SetChaseParameters 方法,用來設定一些不常改變的追蹤參數:追蹤距離和速度。
另外可放一些經常更新的位置和方向參數~
// 追蹤參數 float desiredChaseDistance; float minChaseDistance; float maxChaseDistance; float chaseSpeed; Vector3 chasePosition; public Vector3 ChasePosition { get { return chasePosition; } set { chasePosition = value; } } Vector3 chaseDirection; public Vector3 ChaseDirection { get { return chaseDirection; } set { chaseDirection = value; } } public void SetChaseParameters(float chaseSpeed, float desiredChaseDistance, float minChaseDistance, float maxChaseDistance){ this.chaseSpeed = chaseSpeed; this.desiredChaseDistance = desiredChaseDistance; this.minChaseDistance = minChaseDistance; this.maxChaseDistance = maxChaseDistance; } |
更新攝影機的位置
每次攝影機在更新時,都應該要重新計算位置。攝影機的位置應該等同於…追蹤點 – 追蹤方向 * 追蹤距離(攝影機到追蹤點的距離)。
如同示意圖,攝影機的期望位置就應該是最終位置。
為了讓攝影機平滑地在最遠距離(maxChaseDistance)和最短距離(minChaseDistance)之間移動,需要利用線性內插的方式計算新位置。
Vector3 targetPosition = chasePosition; Vector3 desiredCameraPosition = chasePosition – chaseDirection * desiredChaseDistance; float interpolatedSpeed = MathHelper.Clamp(chaseSpeed * desiredCameraPosition = Vector3.Lerp(position, desiredCameraPosition, |
線性權重的計算是由上一次更新的時間差乘上攝影機的速度,權重需要壓縮到 0.0 ~ 1.0 之間,接著再用 Vector3 的 Lerp() 計算線性內插值。
創造一個 UpdateFollowPosition 方法,用來更新被追蹤的位置。
private void UpdateFollowPosition(float elapsedTimeSeconds, bool interpolate) { Vector3 targetPosition = chasePosition; Vector3 desiredCameraPosition = chasePosition– chaseDirection * desiredChaseDistance; if (interpolate) { float interpolatedSpeed = MathHelper.Clamp( chaseSpeed * elapsedTimeSeconds, 0.0f, 1.0f); desiredCameraPosition = Vector3.Lerp(position, // 限制距離 |
這個 UpdateFollowPositionmethod 方法裡有個 interpolate 參數,是用來決定是否使用線性內插計算攝影機的位置。
如果攝影機第一次追蹤目標,你需要將 interpolate 設為 false ,將攝影機放到定位。
當你使用內插計算出攝影機的位置後,接著要確保位置介於最短距離和最大距離之內。
這個檢測可以避免在被追蹤的物體移動過快時,還能準確追蹤著。
使攝影機環繞物件
為了讓我們的攝影機可以沿著物件環繞。所以,要在加入兩個參數給 ThirdPersonCamera 類別。
// 可允許的最大旋轉角度 public static float MAX_ROTATE = 30.0f; // 目前在攝影機軸上的選轉角度 Vector3 eyeRotate; // 在攝影機軸上的旋轉速度 public Vector3 EyeRotateVelocity |
攝影機允許的旋轉角度介於 -MAX_ROTATE 和 MAX_ROTATE 之間。
eyeRotate 向量儲存目前旋轉的角度,X、Y 和 Z 分別代表在攝影機三軸上的旋轉角度。
最後,在攝影機旋轉角度更新,儲存旋轉速度到 eyeRotateVelocity 裡面。
接著,為了計算攝影機的檢視矩陣(viewmatrix),需要覆寫 BaseCamera 的 UpdateView 方法。
記住,UpdateView 是在屬性 View 被 get 時,而且需要更新時才會呼叫的。
protected override void UpdateView() { Vector3 newPosition = Position – Target; // 計算攝影機的新位置,以及依照各自的軸旋轉 viewMatrix = Matrix.CreateLookAt(newPosition + Target, Target, UpVector); |
在覆寫 UpdateView 時就要考慮到攝影機的旋轉去計算它的位置。
攝影機的旋轉角度記錄在 eyeRotation 裡面。
要讓攝影機依照自己的任一軸旋轉時,需要使用 CreateFromAxisAngle 產生一個旋轉矩陣。
然後,將 X、Y 和 Z 三軸的旋轉矩陣組合,計算出最終矩陣。