一個第三人稱遊戲相機的實現(基於rust語言和cgmath庫)

    我在學校時就對角色扮演類3D遊戲感興趣,畢業那會研究過第三人稱視角的遊戲相機的實現(基於D3D),但因爲沒有想到合適的計算方法,最後實現出來的程序有BUG,而且沒找出緣由。git

    最近看到git有rust寫遊戲的示例,因而就想再嘗試解決這個問題,發現cgmath庫作矩陣運算很是方便,順便也找到一個自認爲比較不錯的解決辦法。函數

    第三人稱遊戲相機的特色是,不管相機移動或旋轉,視點始終在屏幕中心的某個點(不會做圖,只能先語言描述了)。即在遊戲角色不移動的狀況下旋轉視角,相機始終是繞着遊戲玩家在一個球面上運動。cgmath提供了一個計算取景矩陣的函數:學習

pub fn look_at(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S>

該函數接受3個參數,eye表示眼睛的位置,即相機的位置,是3維空間的一個點,center表示視線的焦點,在遊戲裏能夠認爲是遊戲玩家的位置,是3維空間的一個點,up表示相機向上的方向,是一個向量。遊戲視角的旋轉變化,實際上就是要計算這3個值。通常遊戲視角旋轉由鼠標控制,咱們假設鼠標在屏幕x軸方向移動了x,y軸方向移動了y,咱們來計算旋轉後的取景矩陣(假設鼠標移動的距離與相機旋轉的角度之間的係數爲1,而且假設玩家不移動,簡化問題)。spa

    爲了計算這3個參數,我首先由 center-eye 獲得一個向量,即相機的視線向量sight。旋轉的過程當中,center點的位置是不變的,因此咱們能夠先對sight向量繞center點做旋轉,獲得新的sight方向,而後再由center點沿着sight的反方向平移一個距離,就能夠獲得新的eye座標。這裏sight向量繞center點旋轉,實際是分別繞了兩個軸做了旋轉:一個是過center點平行於座標系y軸的軸,另外一個是過center點平行於right軸的軸,right軸是垂直與sight向量,平行於xoz平面的方向向量,right軸能夠由世界座標軸y軸與sight向量叉乘獲得:orm

let world_up: Vector3<S> = Vector3::unit_y();
let right: Vector3<S> = world_up.cross(sight).normalize();

這裏要注意world_up與sight的位置不能反,不然算出來的方向就反了。遊戲

在計算新的sight向量時,爲了計算方便,能夠先將center點平移到世界座標原點來計算,這樣就變成了繞y軸和right軸分別做旋轉。向量繞y軸旋轉函數:遊戲開發

let matrix_up = Matrix4::from_angle_y(Deg(x));//獲得旋轉矩陣
let sight_new = matrix_up.transform_vector(self.sight);//旋轉
self.sight = sight_new.normalize();//規則化

繞right軸旋轉實現:開發

let matrix_right = Matrix4::from_axis_angle(right, Deg(y));
let sight_new = matrix_right.transform_vector(self.sight);
self.sight = sight_new.normalize();

這裏須要注意,若是x,y都不爲0,則將matrix_up * matrix_right的結果用於對sight做旋轉it

let sight_new = matrix.transform_vector(self.sight);
self.sight = sight_new.normalize();

由於浮點運算有偏差,計算次數越少越好。form

    遊戲玩家移動就簡單了,直接對center點做平移,最後計算新的eye座標:

let eye: Point3<S> = Point3::new(
    -(sight.x * length) + focus.x,
    -(sight.y * length) + focus.y,
    -(sight.z * length) + focus.z
);

up向量的計算能夠直接用sight向量與right向量叉乘獲得:

let up: Vector3<S> = sight.cross(right).normalize();

 能夠看到相機的變換隻依據兩個量:sight向量與center座標。這裏認爲eye與center點的距離是常量length,固然真正遊戲裏是一個能夠控制的變量。

    最後計算矩陣(真正取景矩陣還須要與一個相機設置的矩陣相乘)。

let view = Matrix4::look_at(eye, point, up)

    我的極少寫東西,寫的很差還請見諒。我只是對3D圖形這些東西很感興趣,可是又沒有個很好的途徑去學習,走了不少彎路,就好比這個相機的實現,我以前怎麼都找不到相關資料(關於遊戲開發的資料原本就不多)。若是我寫的這點東西能對一樣對遊戲感興趣的新手有幫助的話,我也是很是開心的。歡迎你們留言,吐槽。

相關文章
相關標籤/搜索