zoukankan      html  css  js  c++  java
  • 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);
    }

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

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

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

    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.0f0);
        
    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);
        }
    }

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

    最后是效果图:

  • 相关阅读:
    深度学习代码注解(一)—— mnistdeepauto
    只属于你我的共同记忆
    只属于你我的共同记忆
    道教的认识
    道教的认识
    作家、文学大家、大师的艺术风格
    作家、文学大家、大师的艺术风格
    视频、画面、语言、文字与脑海、心灵
    视频、画面、语言、文字与脑海、心灵
    URAL 1963 Kite 四边形求对称轴数
  • 原文地址:https://www.cnblogs.com/kenkao/p/2088415.html
Copyright © 2011-2022 走看看