Direct3D轮回:构建基于Direct3D的通用摄影机类

Direct3D渲染管线主要完成了三次矩阵变换:
1.世界变换——局部坐标到全局坐标的变换;
2.摄影变换——全局坐标到摄影坐标的变换;
3.投影变换——摄影坐标到投影坐标的变换。
其中的摄影变换我们大都通过封装一个称之为“摄影机”的对象加以实现。
如下即为一个基于Direct3D机制的通用摄影机实现:
/*------------------------------------- 代码清单:D3DCamera.h 来自:http://www.cnblogs.com/kenkao -------------------------------------*/ #include "D3DInit.h" #pragma _disibledevent=> class CD3DCamera { public: CD3DCamera(void); ~CD3DCamera(void); public: D3DXVECTOR3 GetCameraPos() {return m_cameraPosition;} //---获得摄影机位置 void SetCameraPos(D3DXVECTOR3 cameraPos) {m_cameraPosition = cameraPos;} //---设置摄影机位置 D3DXVECTOR3 GetCameraTar() {return m_cameraTarget;} //---获得摄影机目标 void SetCameraTar(D3DXVECTOR3 cameraTar) {m_cameraTarget = cameraTar;} //---设置摄影机目标 D3DXVECTOR3 GetCameraUp() {return m_cameraUp;} //---获得摄影机Y方向 void SetCameraUp(D3DXVECTOR3 cameraUp) {m_cameraUp = cameraUp;} //---设置摄影机Y方向 D3DMATRIX GetViewMatrix() {return m_viewMatrix;} //---获得摄影矩阵 public: void Update(); //---更新摄影机 void Release(); //---释放摄影机 private: void UpdateCamera(); //---更新摄影机(私有) void RotateManager(); //---处理旋转(私有) void MoveManager(); //---处理平移(私有) private: D3DXVECTOR3 m_cameraPosition; //---摄影机位置 D3DXVECTOR3 m_cameraTarget; //---摄影机目标 D3DXVECTOR3 m_cameraUp; //---摄影机Y方向 D3DXMATRIX m_viewMatrix; //---摄影机摄影矩阵 float m_rotateSpeed; //---旋转速度 float m_moveSpeed; //---平移速度 float m_rotateRight; //---水平方向旋转(以右为正) float m_rotateUp; //---垂直方向旋转(以上为正) float m_moveForward; //---前后方向移动(以前为正) float m_moveRight; //---左右方向移动(以右为正) float m_moveUp; //---上下方向移动(以上为正) POINT m_nowMousePos; //---当前鼠标位置 POINT m_originMousePos; //---前次鼠标位置 };
/*------------------------------------- 代码清单:D3DCamera.cpp 来自:http://www.cnblogs.com/kenkao -------------------------------------*/ #include "StdAfx.h" #include "D3DCamera.h" #include "D3DGame.h" extern IDirect3DDevice9 *g_pD3DDevice; extern CMouseInput *g_pMouseInput; extern CKeyboardInput *g_pKeyboardInput; CD3DCamera::CD3DCamera(void) : m_cameraPosition(D3DXVECTOR3_ZERO), m_cameraTarget(0.0f,0.0f,100.0f), m_cameraUp(D3DXVECTOR3_UP), m_rotateSpeed(0.005f), m_moveSpeed(0.1f), m_rotateRight(0.0f), m_rotateUp(0.0f), m_moveForward(0.0f), m_moveRight(0.0f), m_moveUp(0.0f) { g_pMouseInput->GetPosition(m_originMousePos); } CD3DCamera::~CD3DCamera(void) { } void CD3DCamera::Update() { //---先处理旋转 RotateManager(); //---然后在【旋转的基础上】处理平移 MoveManager(); //---最后更新相机 UpdateCamera(); } void CD3DCamera::Release() { } void CD3DCamera::RotateManager() { // 获得鼠标当前位置 g_pMouseInput->GetPosition(m_nowMousePos); // 如果鼠标右键按下 if(g_pMouseInput->RightButton() == BUTTONSTATE_PRESSED) { // X方向旋转量 float Xdif = m_nowMousePos.x-m_originMousePos.x; // Y方向旋转量 float Ydif = m_nowMousePos.y-m_originMousePos.y; // 分别累积到水平与垂直方向旋转 m_rotateRight += m_rotateSpeed * Xdif; m_rotateUp += m_rotateSpeed * Ydif; } // 更新前次鼠标位置 m_originMousePos = m_nowMousePos; } void CD3DCamera::MoveManager() { // 前移 if (g_pKeyboardInput->IsKeyDown(DIK_W) || g_pKeyboardInput->IsKeyDown(DIK_UP)) m_moveForward = m_moveSpeed; // 后移 if (g_pKeyboardInput->IsKeyDown(DIK_S) || g_pKeyboardInput->IsKeyDown(DIK_DOWN)) m_moveForward = -m_moveSpeed; // 左移 if (g_pKeyboardInput->IsKeyDown(DIK_D) || g_pKeyboardInput->IsKeyDown(DIK_RIGHT)) m_moveRight = +m_moveSpeed; // 右移 if (g_pKeyboardInput->IsKeyDown(DIK_A) || g_pKeyboardInput->IsKeyDown(DIK_LEFT)) m_moveRight = -m_moveSpeed; } void CD3DCamera::UpdateCamera() { // 注意:垂直方向绕X轴转动;水平方向绕Y轴转动。这个不要弄反^ ^ D3DXMATRIX diffx; D3DXMatrixRotationX(&diffx,m_rotateUp); D3DXMATRIX diffy; D3DXMatrixRotationY(&diffy,m_rotateRight); D3DXMATRIX diff = diffx * diffy; D3DXVECTOR3 Adiff; D3DXVec3TransformCoord(&Adiff,&D3DXVECTOR3_ZERO,&diff); D3DXVECTOR3 Sdiff; D3DXVec3TransformCoord(&Sdiff,&(D3DXVECTOR3_FORWARD*100.0f),&diff); //---根据旋转处理Target m_cameraTarget = m_cameraPosition + Adiff + Sdiff; //---m_cameraUp暂且不做处理,Hero站在地面上头顶永远向上,囧~ //---如何支持飞行态大家自行推导即可。 //---根据平移处理Position D3DXVECTOR3 Xdiff; D3DXVec3TransformCoord(&Xdiff,&D3DXVECTOR3(m_moveRight,0.0f,0.0f),&diff); D3DXVECTOR3 Zdiff; D3DXVec3TransformCoord(&Zdiff,&D3DXVECTOR3(0.0f,0.0f,m_moveForward),&diff); // 计算得摄影变换矩阵,这也是摄影机所有运算的最终结果 m_cameraPosition = m_cameraPosition + Xdiff + Zdiff; D3DXMatrixLookAtLH(&m_viewMatrix,&(m_cameraPosition + Adiff),&m_cameraTarget,&m_cameraUp); m_moveForward = 0; m_moveRight = 0; }
代码比较基础,给出了相对完整的注释~
矩阵运算的相关API说明,大家可以参看我在小组中发的这篇帖子:http://space.cnblogs.com/group/topic/32546/
需要说明一点问题:矩阵乘法不满足交换律。是以旋转处理及平移处理两方法调用的先后次序不可颠倒~
摄影机构建完毕之后,我们可以再简单构建一个参照系对象,来验证摄影机工作是否正常:
/*------------------------------------- 代码清单:CoordCross.h 来自:http://www.cnblogs.com/kenkao -------------------------------------*/ #include "D3DInit.h" #pragma _disibledevent=> class CCoordCross { public: CCoordCross(void); ~CCoordCross(void); public: void Draw(); void Release(); private: void InitVertices(); private: IDirect3DVertexBuffer9* m_pVB; };
/*------------------------------------- 代码清单:CoordCross.吹泡泡~ 囧~ 来自:http://www.cnblogs.com/kenkao -------------------------------------*/ #include "StdAfx.h" #include "CoordCross.h" #include "D3DGame.h" extern IDirect3DDevice9 *g_pD3DDevice; struct VertexPositionColor{ VertexPositionColor(){} VertexPositionColor(float x, float y, float z, D3DCOLOR color){ _x = x; _y = y; _z = z; _color = color; } float _x, _y, _z; D3DCOLOR _color; static const DWORD FVF; }; const DWORD VertexPositionColor::FVF = (D3DFVF_XYZ | D3DFVF_DIFFUSE); CCoordCross::CCoordCross(void):m_pVB(0) { InitVertices(); } CCoordCross::~CCoordCross(void) { } void CCoordCross::InitVertices() { g_pD3DDevice->CreateVertexBuffer( 18 * sizeof(VertexPositionColor), D3DUSAGE_WRITEONLY, VertexPositionColor::FVF, D3DPOOL_MANAGED, &m_pVB, 0); VertexPositionColor* pVertices; m_pVB->Lock(0,0,(void**)&pVertices,0); pVertices[0] = VertexPositionColor(0.0f,0.0f,0.0f,D3DXCOLOR_WHITE); pVertices[1] = VertexPositionColor(5.0f,0.0f,0.0f,D3DXCOLOR_WHITE); pVertices[2] = VertexPositionColor(5.0f,0.0f,0.0f,D3DXCOLOR_WHITE); pVertices[3] = VertexPositionColor(4.5f,0.5f,0.0f,D3DXCOLOR_WHITE); pVertices[4] = VertexPositionColor(5.0f,0.0f,0.0f,D3DXCOLOR_WHITE); pVertices[5] = VertexPositionColor(4.5f,-0.5f,0.0f,D3DXCOLOR_WHITE); pVertices[6] = VertexPositionColor(0.0f,0.0f,0.0f,D3DXCOLOR_WHITE); pVertices[7] = VertexPositionColor(0.0f,5.0f,0.0f,D3DXCOLOR_WHITE); pVertices[8] = VertexPositionColor(0.0f,5.0f,0.0f,D3DXCOLOR_WHITE); pVertices[9] = VertexPositionColor(0.5f,4.5f,0.0f,D3DXCOLOR_WHITE); pVertices[10] = VertexPositionColor(0.0f,5.0f,0.0f,D3DXCOLOR_WHITE); pVertices[11] = VertexPositionColor(-0.5f,4.5f,0.0f,D3DXCOLOR_WHITE); pVertices[12] = VertexPositionColor(0.0f,0.0f,0.0f,D3DXCOLOR_WHITE); pVertices[13] = VertexPositionColor(0.0f,0.0f,5.0f,D3DXCOLOR_WHITE); pVertices[14] = VertexPositionColor(0.0f,0.0f,5.0f,D3DXCOLOR_WHITE); pVertices[15] = VertexPositionColor(0.0f,0.5f,4.5f,D3DXCOLOR_WHITE); pVertices[16] = VertexPositionColor(0.0f,0.0f,5.0f,D3DXCOLOR_WHITE); pVertices[17] = VertexPositionColor(0.0f,-0.5f,4.5f,D3DXCOLOR_WHITE); m_pVB->Unlock(); } void CCoordCross::Draw() { g_pD3DDevice->SetStreamSource(0,m_pVB,0,sizeof(VertexPositionColor)); g_pD3DDevice->SetFVF(VertexPositionColor::FVF); g_pD3DDevice->DrawPrimitive(D3DPT_LINELIST,0,9); } void CCoordCross::Release() { ReleaseCOM(m_pVB); }
《龙书》中最为基本的基于顶点缓冲区的绘制方法~
如果您有不明白的地方可以翻看《龙书》,或者发表评论,我会尽量给出详尽的解答 ^ ^
最后是我们的主体代码部分:
Direct3D轮回:构建基于Direct3D的通用摄影机类Direct3D轮回:构建基于Direct3D的通用摄影机类D3DGame.cpp /*------------------------------------- 代码清单:D3DGame.cpp 来自:http://www.cnblogs.com/kenkao -------------------------------------*/ #include "StdAfx.h" #include "D3DGame.h" #include "D3DCamera.h" #include "CoordCross.h" #include HINSTANCE g_hInst; HWND g_hWnd; IDirect3D9 *g_pD3D = NULL; IDirect3DDevice9 *g_pD3DDevice = NULL; CMouseInput *g_pMouseInput = NULL; CKeyboardInput *g_pKeyboardInput = NULL; CD3DCamera *g_pD3DCamera = NULL; CCoordCross *g_pCoordCross = NULL; // 鼠标输入单元测试函数 void TestMouseInput(); void TestKeyboardInput(); void Initialize(HINSTANCE hInst, HWND hWnd) { g_hInst = hInst; g_hWnd = hWnd; InitD3D(&g_pD3D, &g_pD3DDevice, hWnd); g_pMouseInput = new CMouseInput; g_pMouseInput->Initialize(hInst,hWnd); g_pKeyboardInput = new CKeyboardInput; g_pKeyboardInput->Initialize(hInst,hWnd); g_pD3DCamera = new CD3DCamera; } void LoadContent() { g_pCoordCross = new CCoordCross; g_pD3DCamera->SetCameraPos(D3DXVECTOR3(3.0f,2.0f,-8.0f)); } void Update() { g_pMouseInput->GetState(); g_pKeyboardInput->GetState(); g_pD3DCamera->Update(); } void Draw() { g_pD3DDevice->SetTransform(D3DTS_VIEW,&g_pD3DCamera->GetViewMatrix()); g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(100,149,237,255), 1.0f, 0); if(SUCCEEDED(g_pD3DDevice->BeginScene())) { g_pCoordCross->Draw(); g_pD3DDevice->EndScene(); } g_pD3DDevice->Present(NULL, NULL, NULL, NULL); } void UnloadContent() { ReleaseCOM(g_pCoordCross); } void Dispose() { ReleaseCOM(g_pD3DCamera); ReleaseCOM(g_pKeyboardInput); ReleaseCOM(g_pMouseInput); ReleaseCOM(g_pD3DDevice); ReleaseCOM(g_pD3D); } void TestMouseInput() { POINT point; g_pMouseInput->GetState(); g_pMouseInput->GetPosition(point); TCHAR tmpText[50]; if(g_pMouseInput->LeftButton()==BUTTONSTATE_PRESSED) { sprintf(tmpText,"鼠标左键已按下,X-Y坐标为(%d,%d)",point.x,point.y); MessageBox(NULL,tmpText,"提示",MB_OK|MB_ICONINFORMATION); } else if(g_pMouseInput->MiddleButton()==BUTTONSTATE_PRESSED) { sprintf(tmpText,"鼠标滚轮已按下,X-Y坐标为(%d,%d)",point.x,point.y); MessageBox(NULL,tmpText,"提示",MB_OK|MB_ICONINFORMATION); } else if(g_pMouseInput->RightButton()==BUTTONSTATE_PRESSED) { sprintf(tmpText,"鼠标右键已按下,X-Y坐标为(%d,%d)",point.x,point.y); MessageBox(NULL,tmpText,"提示",MB_OK|MB_ICONINFORMATION); } } void TestKeyboardInput() { TCHAR tmpText[50]; // 获得键盘输入设备状态 g_pKeyboardInput->GetState(); // 单键检测 if(g_pKeyboardInput->IsKeyDown(DIK_D)) { sprintf(tmpText,"D键被按下"); MessageBox(NULL,tmpText,"提示",MB_OK|MB_ICONINFORMATION); } // 组合键检测 else if(g_pKeyboardInput->IsKeyDown(DIK_A)&g_pKeyboardInput->IsKeyDown(DIK_S)) { sprintf(tmpText,"A&S组合键被按下"); MessageBox(NULL,tmpText,"提示",MB_OK|MB_ICONINFORMATION); } }
保留了两个测试函数,本例中没有用到~
最后是效果图:
Direct3D轮回:构建基于Direct3D的通用摄影机类
Tags: 

延伸阅读

最新评论

发表评论