Directx11學習筆記【十九】 攝像機的實現

本文由zhangbaochong原創,轉載請註明出處:http://www.cnblogs.com/zhangbaochong/p/5785100.htmlhtml

  以前爲了方便觀察場景,咱們採用的方法是鼠標控制旋轉視角和鏡頭拉伸,可是觀察點依然限制在一個球面內,目標點也始終爲座標原點。爲了可以自由的從各個角度、各個位置觀察場景,實現一個第一人稱攝像機是必不可少的。spa

1.攝像機視角矩陣推導

  攝像機在空間有着特定的位置及朝向,它所觀察到的物體取決於物體與攝像機的相對位置。爲了表示攝像機位置,咱們可使用一個3維向量;對於攝像機的的朝向,可使用三個相互垂直的座標軸的唯一地肯定,即右、上、前三個方向。以攝像機爲參考點,即以之爲原點來觀察物體。所以,視角變換,本質上即把場景中全部的物體、連同攝像機,使用相同的變換,使得變換後攝像機位於場景的原點,且其三個座標軸(右、上、前)與世界座標系的X、Y、Z座標軸重合。這時,變換後的全部物體的座標值,即變爲與攝像機的相對位置了。code

       咱們把攝像機位置用[ px, py, pz ]來表示,其三個表示朝向的座標軸分別表示爲[ Rx, Ry, Rz ]、[ Ux, Uy, Uz ]、[ Lx, Ly, Lz ]。而視角變換的目的即把它的這些參數轉換爲:位置[ 0, 0, 0 ],以及三個座標軸:[ 1, 0,0 ]、[ 0, 1, 0 ]、 [ 0, 0, 1 ]。因爲有平移和旋轉同時存在,所以該變換能夠分爲兩步進行:1. 平移到原點;2. 旋轉。orm

       平移操做很簡單,即把[Px,Py, Pz,1]移回到原點,矩陣爲:htm

       

       旋轉操做須要點小技巧。咱們的目的是把三個軸分別轉換成[1,0,0]、[0,1,0]、[0,0,1],令旋轉矩陣爲M,能夠表示爲以下所示:blog

       

       由上面式子能夠看出,左邊的矩陣與M相乘後變爲右邊的單位矩陣。這正是關鍵所在!咱們知道,一個矩陣與它的逆矩陣相乘結果爲單位矩陣,所以,要求矩陣M,咱們能夠求它的逆矩陣。求逆矩陣須要大量的計算,有沒有更好的方法?ip

       答案是有的!有一點須要知道,正交矩陣的逆矩陣等於它的轉置矩陣。而正交矩陣的一個特色:正交矩陣的每行(每列)相互垂直。回來看下咱們左邊的矩陣,每行分別對應了攝像機的三個相互垂直的軸,顯然它正是正交矩陣!好了,這下M的計算,就變成求它的轉置矩陣了。而轉置的計算再簡單不過了,直接給出:get

       

       如今,兩步須要的矩陣都有了,那最終的視角矩陣即兩次轉換的乘積,固然,因爲平移變換的存在,如今要在4x4矩陣了,以下所示:it

       

       結果中P*R、P*U、P*L分別是位置向量與R、U、L三個向量的點積,經過查看左邊的矩陣相乘很容易看出來。io

       OK, 視角矩陣的推導完畢,如今咱們知道:

       任一時刻,經過攝像機位置P(Px,Py,Pz),以及三個座標軸(R,U,L),能夠獲得當前的視角變換矩陣:

       

2.攝像機類的實現

  攝像機參數主要有:位置、三個座標軸、視角矩陣、投影矩陣、生成投影矩陣的四個參數(視角大小,寬高比,近裁剪平面,遠裁剪平面)。

  實現的功能比較簡單,主要實現移動(先後左右移動),視角旋轉(左右搖頭,上下點頭)。

  因爲代碼比較簡單,故再也不詳細說明了:

 1 #pragma once
 2 
 3 #include <Windows.h>
 4 #include <DirectXMath.h>
 5 #include <cmath>
 6 class Camera
 7 {
 8 public:
 9     Camera();
10 
11     //設置攝像機位置
12     void SetPosition(float x, float y, float z) { m_position = DirectX::XMFLOAT3(x, y, z); }
13     void SetPosition(DirectX::FXMVECTOR pos) { DirectX::XMStoreFloat3(&m_position, pos); }
14 
15     //得到攝像機位置方向等相關參數
16     DirectX::XMFLOAT3 GetPosition() const { return m_position; }
17     DirectX::XMFLOAT3 GetRight() { return m_right; }
18     DirectX::XMFLOAT3 GetLook() { return m_look; }
19     DirectX::XMFLOAT3 GetUp() { return m_up; }
20 
21     DirectX::XMVECTOR GetPosotionXM() const { return DirectX::XMLoadFloat3(&m_position); }
22     DirectX::XMVECTOR GetRightXM() const { return DirectX::XMLoadFloat3(&m_right); }
23     DirectX::XMVECTOR GetLookXM() const { return DirectX::XMLoadFloat3(&m_look); }
24     DirectX::XMVECTOR GetUpXM() const { return DirectX::XMLoadFloat3(&m_up); }
25 
26     //得到投影相關參數
27     float GetNearZ() const { return m_nearZ; }
28     float GetFarZ() const { return m_farZ; }
29     float GetFovY() const { return m_fovY; }
30     float GetFovX() const { return atan(m_aspect * tan(m_fovY * 0.5f)) * 2.f; }
31     float GetAspect() const { return m_aspect; }
32 
33     //得到視圖投影矩陣
34     DirectX::XMMATRIX GetView() const { return DirectX::XMLoadFloat4x4(&m_view); }
35     DirectX::XMMATRIX GetProj() const { return DirectX::XMLoadFloat4x4(&m_proj); }
36     DirectX::XMMATRIX GetViewProj() const { return XMLoadFloat4x4(&m_view) * XMLoadFloat4x4(&m_proj); }
37 
38     //設置投影矩陣
39     void SetLens(float fovY, float aspect, float nearz, float farz);
40 
41     //設置視角矩陣
42     void LookAtXM(DirectX::FXMVECTOR pos, DirectX::FXMVECTOR lookAt, DirectX::FXMVECTOR worldUp);
43     void LookAt(const DirectX::XMFLOAT3& pos, const DirectX::XMFLOAT3& lookAt, 
44         const DirectX::XMFLOAT3& worldUp);
45 
46     //基本操做
47     void Walk(float dist);            //先後行走
48     void Strafe(float dist);            //左右平移
49     void Pitch(float angle);            //上下點頭
50     void RotateY(float angle);        //左右搖頭
51 
52     //更新矩陣
53     void UpdateViewMatrix();
54 private:
55     DirectX::XMFLOAT3 m_right;        //位置和三個座標軸
56     DirectX::XMFLOAT3 m_up;
57     DirectX::XMFLOAT3 m_look;
58     DirectX::XMFLOAT3 m_position;
59 
60     float m_aspect;                    //投影相關參數
61     float m_fovY;
62     float m_nearZ;
63     float m_farZ;
64 
65     DirectX::XMFLOAT4X4 m_view;        //視角矩陣
66     DirectX::XMFLOAT4X4 m_proj;        //投影矩陣
67 };

 

  1 #include "Camera.h"
  2 using namespace DirectX;
  3 
  4 Camera::Camera():
  5     m_position(0.f,0.f,0.f),
  6     m_look(0.f,0.f,1.f),
  7     m_up(0.f,1.f,0.f),
  8     m_right(1.f,0.f,0.f)
  9 {
 10     SetLens(0.25*XM_PI, 800.f / 600, 1.f, 1000.f);
 11 }
 12 
 13 //設置投影矩陣
 14 void Camera::SetLens(float fovY, float aspect, float nearz, float farz)
 15 {
 16     m_fovY = fovY;
 17     m_aspect = aspect;
 18     m_nearZ = nearz;
 19     m_farZ = farz;
 20     XMMATRIX P = XMMatrixPerspectiveFovLH(fovY, aspect, nearz, farz);
 21     XMStoreFloat4x4(&m_proj, P);
 22 }
 23 
 24 //設置視角矩陣
 25 void Camera::LookAtXM(DirectX::FXMVECTOR pos, DirectX::FXMVECTOR lookAt, DirectX::FXMVECTOR worldUp)
 26 {
 27     XMVECTOR look = XMVector3Normalize(lookAt - pos);
 28     XMVECTOR right = XMVector3Normalize(XMVector3Cross(worldUp, look));
 29     XMVECTOR up = XMVector3Cross(look, right);
 30 
 31     XMStoreFloat3(&m_position, pos);
 32     XMStoreFloat3(&m_look, look);
 33     XMStoreFloat3(&m_right, right);
 34     XMStoreFloat3(&m_up, up);
 35 }
 36 
 37 void Camera::LookAt(const DirectX::XMFLOAT3& pos, const DirectX::XMFLOAT3& lookAt, 
 38     const DirectX::XMFLOAT3& worldUp)
 39 {
 40     XMVECTOR p = XMLoadFloat3(&pos);
 41     XMVECTOR l = XMLoadFloat3(&lookAt);
 42     XMVECTOR u = XMLoadFloat3(&worldUp);
 43 
 44     LookAtXM(p, l, u);
 45 }
 46 
 47 //先後行走
 48 void Camera::Walk(float dist)
 49 {
 50     XMVECTOR pos = XMLoadFloat3(&m_position);
 51     XMVECTOR look = XMLoadFloat3(&m_look);
 52     pos += look * XMVectorReplicate(dist); //XMVectorReplicate(x)返回XMVector(x,x,x,x)
 53     XMStoreFloat3(&m_position, pos);
 54 }
 55 
 56 //左右平移
 57 void Camera::Strafe(float dist)
 58 {
 59     XMVECTOR pos = XMLoadFloat3(&m_position);
 60     XMVECTOR right = XMLoadFloat3(&m_right);
 61     pos += right * XMVectorReplicate(dist);
 62 
 63     XMStoreFloat3(&m_position, pos);
 64 }
 65 
 66 //上下點頭
 67 void Camera::Pitch(float angle)
 68 {
 69     XMMATRIX rotation = XMMatrixRotationAxis(XMLoadFloat3(&m_right), angle);
 70                             //向量矩陣相乘
 71     XMStoreFloat3(&m_up, XMVector3TransformNormal(XMLoadFloat3(&m_up), rotation));
 72     XMStoreFloat3(&m_look, XMVector3TransformNormal(XMLoadFloat3(&m_look), rotation));
 73 }
 74 
 75 //左右搖頭
 76 void Camera::RotateY(float angle)
 77 {
 78     XMMATRIX rotation = XMMatrixRotationY(angle);
 79 
 80     XMStoreFloat3(&m_right, XMVector3TransformNormal(XMLoadFloat3(&m_right), rotation));
 81     XMStoreFloat3(&m_up, XMVector3TransformNormal(XMLoadFloat3(&m_up), rotation));
 82     XMStoreFloat3(&m_look, XMVector3TransformNormal(XMLoadFloat3(&m_look), rotation));
 83 }
 84 
 85 //更新視角矩陣
 86 void Camera::UpdateViewMatrix()
 87 {
 88     XMVECTOR r = XMLoadFloat3(&m_right);
 89     XMVECTOR u = XMLoadFloat3(&m_up);
 90     XMVECTOR l = XMLoadFloat3(&m_look);
 91     XMVECTOR p = XMLoadFloat3(&m_position);
 92 
 93     r = XMVector3Normalize(XMVector3Cross(u, l));
 94     u = XMVector3Normalize(XMVector3Cross(l, r));
 95     l = XMVector3Normalize(l);
 96 
 97     float x = -XMVectorGetX(XMVector3Dot(p, r));
 98     float y = -XMVectorGetX(XMVector3Dot(p, u));
 99     float z = -XMVectorGetX(XMVector3Dot(p, l));
100 
101     XMStoreFloat3(&m_right, r);
102     XMStoreFloat3(&m_up, u);
103     XMStoreFloat3(&m_look, l);
104     XMStoreFloat3(&m_position, p);
105 
106     m_view(0, 0) = m_right.x;    m_view(0, 1) = m_up.x;    m_view(0, 2) = m_look.x;     m_view(0, 3) = 0;
107     m_view(1, 0) = m_right.y;    m_view(1, 1) = m_up.y;    m_view(1, 2) = m_look.y;     m_view(1, 3) = 0;
108     m_view(2, 0) = m_right.z;    m_view(2, 1) = m_up.z;    m_view(2, 2) = m_look.z;     m_view(2, 3) = 0;
109     m_view(3, 0) = x;            m_view(3, 1) = y;         m_view(3, 2) = z;            m_view(3, 3) = 1;
110 }

3.攝像機的使用

  例子是上個demo,只不過是把控制視角的方式換成了剛實現的攝像機而已。

  代碼下載:http://files.cnblogs.com/files/zhangbaochong/CameraDemo.zip

相關文章
相關標籤/搜索