• Direct3D轮回:基于.X文件的网格加载及渲染


    DX9.0对.X文件提供了相当丰富的支持,包括高级骨骼动画的解析及渲染。

    DX10之后,.X开始渐渐淡出人们的视野,取而代之的是各种自定义的网格数据文件。

    虽然.X文件不再被广泛支持,但其数据定义仍具有相当的参考价值和意义~

    本篇简单实现了.X网格的加载及渲染,意在服务于后续章节,感兴趣的朋友可以简单参考一下~

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

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

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

    #include 
    "D3DInit.h"

    #pragma once

    class CSimpleXMesh
    {
    public:
        CSimpleXMesh(
    void);
        
    ~CSimpleXMesh(void);
    public:
        
    bool LoadXMesh(TCHAR* szXFileName);        // 加载.X网格
        void DrawXMesh(const D3DXVECTOR3& pos);    // 绘制.X网格
        void Release();                            // 释放.X网格
    private:
        ID3DXBuffer
    * m_pAdjacencyBuffer;           // 邻接三角形信息缓冲区
        ID3DXBuffer* m_pMaterialBuffer;            // 材质缓冲区
        D3DMATERIAL9 *m_pD3DMaterialArray;         // 材质数组
        IDirect3DTexture9 **m_ppDirect3DTextureArray;  // 纹理数组
        DWORD m_dwMaterials;                       // 材质数
        ID3DXMesh* m_pD3DXMesh;                    // .X网格对象指针
    };
    SimpleXMesh.cpp
    /*-------------------------------------

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

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

    #include 
    "StdAfx.h"
    #include 
    "SimpleXMesh.h"
    #include 
    "D3DGame.h"

    extern IDirect3DDevice9 *g_pD3DDevice;

    CSimpleXMesh::CSimpleXMesh(
    void):m_pAdjacencyBuffer(NULL),
                                     m_pMaterialBuffer(NULL),
                                     m_pD3DMaterialArray(NULL),
                                     m_ppDirect3DTextureArray(NULL),
                                     m_dwMaterials(
    0),
                                     m_pD3DXMesh(NULL)
    {

    }

    CSimpleXMesh::
    ~CSimpleXMesh(void)
    {

    }

    bool CSimpleXMesh::LoadXMesh(TCHAR* szXFileName){
        
    // 加载X网格
        if(FAILED(D3DXLoadMeshFromX(
            szXFileName,                            
    //.X文件名
            D3DXMESH_MANAGED,                       //内存托管模式
            g_pD3DDevice,                           //Direct3D设备
            &m_pAdjacencyBuffer,                    //邻接三角形信息缓冲区指针
            &m_pMaterialBuffer,                     //材质缓冲区指针
            0,                                      //特效缓冲区指针,由于没有用到特效,我们在这里置0即可
            &m_dwMaterials,                         //材质数
            &m_pD3DXMesh                            //得到的X网格
            ))){
                
    return false;
        }
        
    // 错误判断
        if(m_pMaterialBuffer==NULL || m_dwMaterials==0)  
            
    return false;
        
    // 获得材质缓冲区指针
        D3DXMATERIAL* pD3DXMaterial=(D3DXMATERIAL*)m_pMaterialBuffer->GetBufferPointer();
        
    if(pD3DXMaterial!=NULL){
            
    // 初始化材质数组
            m_pD3DMaterialArray=new D3DMATERIAL9[m_dwMaterials];
            
    // 初始化纹理数组
            m_ppDirect3DTextureArray=new IDirect3DTexture9*[m_dwMaterials];
            
    // 遍历材质缓冲区,填充材质及纹理数组
            for(DWORD i=0;i<m_dwMaterials;i++){
                m_pD3DMaterialArray[i]
    =pD3DXMaterial[i].MatD3D;
                
    if(pD3DXMaterial[i].pTextureFilename!=NULL)
                {
                    
    if(FAILED(D3DXCreateTextureFromFile(g_pD3DDevice,pD3DXMaterial[i].pTextureFilename,&m_ppDirect3DTextureArray[i]))){
                        m_ppDirect3DTextureArray[i]
    =NULL;
                    }
                }
                
    else
                {
                    m_ppDirect3DTextureArray[i]
    =NULL;
                }
            }
        }
        
    // 网格数据优化
        m_pD3DXMesh->OptimizeInplace(
            D3DXMESHOPT_COMPACT  
    |
            D3DXMESHOPT_ATTRSORT 
    |
            D3DXMESHOPT_VERTEXCACHE,                           
    //优化模式,具体参看SDK
            (DWORD*)m_pAdjacencyBuffer->GetBufferPointer(),    //邻接三角形信息缓冲区指针
            NULL, NULL, NULL);                                 //参看SDK

        
    // 有效数据已经填充到材质及纹理数组,释放材质缓冲区
        m_pMaterialBuffer->Release();
        
    // 网格数据优化完毕,释放邻接三角形信息缓冲区
        m_pAdjacencyBuffer->Release();
        
    // 当然,这两个缓冲区的释放放到最后的Release函数里也没有问题 ^ ^
        return true;
    }

    void CSimpleXMesh::DrawXMesh(const D3DXVECTOR3& pos)
    {
        
    // 根据位置重新设定世界矩阵
        D3DXMATRIX posMatrix;
        D3DXMatrixTranslation(
    &posMatrix,pos.x,pos.y,pos.z);
        g_pD3DDevice
    ->SetTransform(D3DTS_WORLD,&posMatrix);
        
    // 绘制X网格
        for(DWORD i=0;i<m_dwMaterials;i++)
        {
            g_pD3DDevice
    ->SetMaterial(&m_pD3DMaterialArray[i]);
            g_pD3DDevice
    ->SetTexture(0,m_ppDirect3DTextureArray[i]);
            m_pD3DXMesh
    ->DrawSubset(i);
        }
        
    // 还原世界矩阵
        D3DXMatrixTranslation(&posMatrix,0,0,0);
        g_pD3DDevice
    ->SetTransform(D3DTS_WORLD,&posMatrix);
    }

    void CSimpleXMesh::Release(){
        
    // 释放纹理数组
        for(DWORD i=0;i<m_dwMaterials;i++){
            ReleaseCOM(m_ppDirect3DTextureArray[i]);
        }
        delete[] m_ppDirect3DTextureArray;
        
    // 释放材质数组
        delete[] m_pD3DMaterialArray;
        
    // 释放网格对象
        ReleaseCOM(m_pD3DXMesh);
    }

    注释比较详尽,完全参考了《龙书》里的例子。

    简单说明一下D3DXMATERIAL结构。如下为SDK中关于D3DXMATERIAL的结构定义:

    typedef struct _D3DXMATERIAL
    {
        D3DMATERIAL9  MatD3D;
        LPSTR         pTextureFilename;
    } D3DXMATERIAL;

    该结构专门用于.X中材质信息读取,其中MatD3D是真正的材质信息,pTextureFilename则是此材质关联的纹理名称,需要调用D3DXCreateTextureFromFile来生成真正的纹理对象。相关的API说明可以参看这篇帖子:http://space.cnblogs.com/group/topic/32953/

    如果大家还有什么不明白的地方,可以参看龙书,也可以在下方留言,我会尽量给予详尽的解答 ^ ^

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

    D3DGame.cpp
    /*-------------------------------------

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

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

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

    HINSTANCE  g_hInst;
    HWND       g_hWnd;
    D3DXMATRIX g_matProjection;
    IDirect3D9       
    *g_pD3D        = NULL;
    IDirect3DDevice9 
    *g_pD3DDevice  = NULL;
    CMouseInput      
    *g_pMouseInput = NULL;
    CKeyboardInput   
    *g_pKeyboardInput = NULL;
    CD3DCamera       
    *g_pD3DCamera  = NULL;
    CCoordCross      
    *g_pCoordCross = NULL;
    CSimpleXMesh     
    *g_pSimpleXMesh = NULL;

    // 鼠标输入单元测试函数
    void TestMouseInput();
    // 键盘输入单元测试函数
    void TestKeyboardInput();

    // Mesh特效
    void BeginEffect();
    void EndEffect();
    D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3
    * direction, D3DXCOLOR* color);

    void Initialize(HINSTANCE hInst, HWND hWnd)
    {
        g_hInst 
    = hInst;
        g_hWnd  
    = hWnd;
        InitD3D(
    &g_pD3D, &g_pD3DDevice, g_matProjection, 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));
        g_pSimpleXMesh 
    = new CSimpleXMesh;
        g_pSimpleXMesh
    ->LoadXMesh("bigship1.x");
    }

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

            BeginEffect();
            g_pSimpleXMesh
    ->DrawXMesh(D3DXVECTOR3(0.0f,0.0f,0.0f));
            EndEffect();

            g_pD3DDevice
    ->EndScene();
        }
        g_pD3DDevice
    ->Present(NULL, NULL, NULL, NULL);
    }

    void UnloadContent()
    {
        ReleaseCOM(g_pSimpleXMesh);
        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);
        }
    }

    void BeginEffect()
    {
        D3DXVECTOR3 dir(
    -1.0f-1.0f1.0f);
        D3DXCOLOR col(
    1.0f1.0f1.0f1.0f);
        D3DLIGHT9 light 
    = InitDirectionalLight(&dir, &col);
        g_pD3DDevice
    ->SetLight(0&light);
        g_pD3DDevice
    ->SetRenderState(D3DRS_LIGHTING,         TRUE);
        g_pD3DDevice
    ->LightEnable(0true);
        g_pD3DDevice
    ->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
        g_pD3DDevice
    ->SetRenderState(D3DRS_SPECULARENABLE,   TRUE);
    }

    void EndEffect()
    {
        g_pD3DDevice
    ->SetRenderState(D3DRS_LIGHTING,         FALSE);
        g_pD3DDevice
    ->SetRenderState(D3DRS_NORMALIZENORMALS, FALSE);
        g_pD3DDevice
    ->SetRenderState(D3DRS_SPECULARENABLE,   FALSE);
    }

    D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3
    * direction, D3DXCOLOR* color)
    {
        D3DLIGHT9 light;
        ::ZeroMemory(
    &light, sizeof(light));
        light.Type      
    = D3DLIGHT_DIRECTIONAL;
        light.Ambient   
    = *color * 0.4f;
        light.Diffuse   
    = *color;
        light.Specular  
    = *color * 0.6f;
        light.Direction 
    = *direction;
        
    return light;
    }

    BeginEffect和EndEffect只是为我们的X网格添加了一个灯光特效~

    最后是效果图:

    这架新型战机相信熟悉龙书的朋友一定不会陌生~ 呵呵~

  • 相关阅读:
    ES6常用新特性
    jquery基础总结 -- 转载
    正则验证
    prop attr 到底哪里不一样?
    分页导航 获取当前页码 的 分页导航哦
    使用Bootatrap的心得
    使用padding来合理布局自己的容器类
    使用angular-ui-router替代ng-router
    使用jitpack来获取github上的开源项目
    关于移动端的UI事件分类
  • 原文地址:https://www.cnblogs.com/kenkao/p/2093228.html
Copyright © 2020-2023  润新知