您的位置:首页 > 其它

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

2011-06-23 20:30 218 查看
Direct3D渲染管线主要完成了三次矩阵变换:

1.世界变换——局部坐标到全局坐标的变换;

2.摄影变换——全局坐标到摄影坐标的变换;

3.投影变换——摄影坐标到投影坐标的变换。

其中的摄影变换我们大都通过封装一个称之为“摄影机”的对象加以实现。

如下即为一个基于Direct3D机制的通用摄影机实现:

/*-------------------------------------

代码清单:D3DCamera.h
来自:http://www.cnblogs.com/kenkao

-------------------------------------*/

#include "D3DInit.h"

#pragma once

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()
{
//---先累计旋转量
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);

//---而后在旋转基础上累计平移量
D3DXVECTOR3 Xdiff;
D3DXVec3TransformCoord(&Xdiff,&D3DXVECTOR3(m_moveRight,0.0f,0.0f),&diff);
D3DXVECTOR3 Zdiff;
D3DXVec3TransformCoord(&Zdiff,&D3DXVECTOR3(0.0f,0.0f,m_moveForward),&diff);

//---根据平移计算Position
m_cameraPosition = m_cameraPosition + Xdiff + Zdiff;
//---在已获得平移的基础上,根据旋转计算Target
m_cameraTarget = m_cameraPosition + Adiff + Sdiff;

//---计算得最终的摄影矩阵

D3DXMatrixLookAtLH(&m_viewMatrix,&(m_cameraPosition + Adiff),&m_cameraTarget,&m_cameraUp);
m_moveForward = 0;
m_moveRight = 0;
}
代码比较基础,给出了相对完整的注释~

矩阵运算的相关API说明,大家可以参看我在小组中发的这篇帖子:http://space.cnblogs.com/group/topic/32546/

需要说明一点问题:矩阵乘法不满足交换律。是以UpdateCamera()函数中关于旋转量与平移量的累计次序不可颠倒~

摄影机构建完毕之后,我们可以再简单构建一个参照系对象,来验证摄影机工作是否正常:

/*-------------------------------------

代码清单:CoordCross.h
来自:http://www.cnblogs.com/kenkao

-------------------------------------*/

#include "D3DInit.h"

#pragma once

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);
}
《龙书》中最为基本的基于顶点缓冲区的绘制方法~

如果您有不明白的地方可以翻看《龙书》,或者发表评论,我会尽量给出详尽的解答 ^ ^

最后是我们的主体代码部分:

D3DGame.cpp

/*-------------------------------------

代码清单:D3DGame.cpp
来自:http://www.cnblogs.com/kenkao

-------------------------------------*/

#include "StdAfx.h"
#include "D3DGame.h"
#include "D3DCamera.h"
#include "CoordCross.h"
#include <stdio.h>

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);
}
}
保留了两个测试函数,本例中没有用到~

最后是效果图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: