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

DX9.0对.X文件提供了相当丰富的支持,包括高级骨骼动画的解析及渲染。
DX10之后,.X开始渐渐淡出人们的视野,取而代之的是各种自定义的网格数据文件。
虽然.X文件不再被广泛支持,但其数据定义仍具有相当的参考价值和意义~
本篇简单实现了.X网格的加载及渲染,意在服务于后续章节,感兴趣的朋友可以简单参考一下~
/*------------------------------------- 代码清单:SimpleXMesh.h 来自:http://www.cnblogs.com/kenkao -------------------------------------*/ #include "D3DInit.h" #pragma _disibledevent=> 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网格对象指针 };
Direct3D轮回:基于.X文件的网格加载及渲染Direct3D轮回:基于.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;iOptimizeInplace( 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;iSetMaterial(&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 注释比较详尽,完全参考了《龙书》里的例子。
简单说明一下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 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.0f, 0); 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.0f, 1.0f); D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f); D3DLIGHT9 light = InitDirectionalLight(&dir, &col); g_pD3DDevice->SetLight(0, &light); g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE); g_pD3DDevice->LightEnable(0, true); 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网格添加了一个灯光特效~
最后是效果图:
Direct3D轮回:基于.X文件的网格加载及渲染
这架新型战机相信熟悉龙书的朋友一定不会陌生~ 呵呵~
Tags: 

延伸阅读

最新评论

发表评论