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

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);
}

《龙书》中最为基本的基于顶点缓冲区的绘制方法~

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

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

Direct3D轮回:构建基于Direct3D的通用摄影机类 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);
    }
}

保留了两个测试函数,本例中没有用到~

最后是效果图:

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

 

你可能感兴趣的:(摄影)