VS2010+DX9+Assimp使用(1)
1.VS2010+DX9情况下加载模型
1.1 总体介绍
网格
绘制3D模型的方法
- 使用顶点缓存和索引缓存进行绘制
DrawPrimitive()、DrawIndexedPrimitive() - 使用网络进行绘制
1.绘制几何体: D3DXCreateBox、D3DXCreateSphere、…
2.手工创建网格: D3DXCreateMeshFVF
3.使用Xfile文件创建网格
1.2主要介绍XFile 网格文件
相应代码如下
加载 XFile 文件
加载 XFile 材质和纹理
#include "d3dUtility.h"
//第1步,引入头文件
#include <fstream>
#include <vector>
//
// Globals
//
IDirect3DDevice9* Device = 0;
const int Width = 640;
const int Height = 480;
//第2步 网格文件指针,材质,贴图
ID3DXMesh* Mesh = 0;
std::vector<D3DMATERIAL9> Mtrls(0);
std::vector<IDirect3DTexture9*> Textures(0);
//
// Framework functions
//
bool Setup()
{
//第3步 网格文件指针,材质,贴图
HRESULT hr = 0;
ID3DXBuffer* adjBuffer = 0;
ID3DXBuffer* mtrlBuffer = 0;
DWORD numMtrls = 0;
hr = D3DXLoadMeshFromX(
"bigship1.x",
//"1.x",
//"car.x",
D3DXMESH_MANAGED,//指定网格文件存入,托管的内存里
Device,
&adjBuffer,//保存每个三角形的邻接信息
&mtrlBuffer,//保存材质
0,
&numMtrls,//保存材质数量
&Mesh);
if(FAILED(hr))
{
::MessageBox(0,"D3DXLoadMeshFromX() - Failed",0,0);
return false;
}
//检查x文件中有没有材质部分,
if(mtrlBuffer != 0 && numMtrls != 0)
{
D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();//有材质部分,就把它们提取出来
for(int i=0; i<numMtrls; i++)
{
mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;
Mtrls.push_back(mtrls[i].MatD3D);
if(mtrls[i].pTextureFilename != 0)
{
IDirect3DTexture9* tex = 0;
D3DXCreateTextureFromFile(Device, mtrls[i].pTextureFilename, &tex);
Textures.push_back(tex);
}else{
Textures.push_back(0);
}
}
}
d3d::Release<ID3DXBuffer*>(mtrlBuffer);
hr = Mesh->OptimizeInplace( //使用OptimizeInplace()进行网格优化后,Mesh 的几何信息将按照属性进行排序,这样各个子集的顶点/索引将组成连续的块
D3DXMESHOPT_ATTRSORT |
D3DXMESHOPT_COMPACT |
D3DXMESHOPT_VERTEXCACHE,
(DWORD*)adjBuffer->GetBufferPointer(),
0,0,0);
d3d::Release<ID3DXBuffer*>(adjBuffer);
if(FAILED(hr))
{
::MessageBox(0,"OptimizeInplace() - FAILED",0,0);
return false;
}
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
第4步 设置灯光
D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);
D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);
D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);
Device->SetLight(0,&light);
Device->LightEnable(0,true);
Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
Device->SetRenderState(D3DRS_SPECULARENABLE, true);
//
// Set camera.
//
D3DXVECTOR3 pos(4.0f, 4.f, -13.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(
&V,
&pos,
&target,
&up);
Device->SetTransform(D3DTS_VIEW, &V);
//
// Set projection matrix.
//
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI * 0.5f, // 90 - degree
(float)Width / (float)Height,
1.0f,
1000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
void Cleanup()
{
}
bool Display(float timeDelta)
{
if( Device )
{
//
// Update: Rotate the cube.
//
D3DXMATRIX xRot;
D3DXMatrixRotationX(&xRot, D3DX_PI * 0.2f);
static float y = 0.0f;
D3DXMATRIX yRot;
D3DXMatrixRotationY(&yRot, y);
y += timeDelta;
if( y >= 6.28f )
y = 0.0f;
D3DXMATRIX World = xRot * yRot;
Device->SetTransform(D3DTS_WORLD, &World);
//
// Render
//
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
Device->BeginScene();
第5步 绘制材质和网格子集
for(int i=0; i<Mtrls.size(); i++)
{
Device->SetMaterial(&Mtrls[i]);
Device->SetTexture(0, Textures[i]);
Mesh->DrawSubset(i);
}
Device->EndScene();
Device->Present(0, 0, 0, 0);
}
return true;
}
//
// WndProc
//
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_DESTROY:
::PostQuitMessage(0);
break;
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
::DestroyWindow(hwnd);
break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
//
// WinMain
//
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE prevInstance,
PSTR cmdLine,
int showCmd)
{
if(!d3d::InitD3D(hinstance,
Width, Height, true, D3DDEVTYPE_HAL, &Device))
{
::MessageBox(0, "InitD3D() - FAILED", 0, 0);
return 0;
}
if(!Setup())
{
::MessageBox(0, "Setup() - FAILED", 0, 0);
return 0;
}
d3d::EnterMsgLoop( Display );
Cleanup();
Device->Release();
return 0;
}
1.3 XFile 网格文件来源
3D 建模工具 ——》 XFile
Maya
3DS Max
…
例如:网上找到fbx文件利用3dmax转换为x文件
1.把fbx文件在3dmax2009 32位打开(文件-导入)
2.把fbx文件在3dmax2009 32位另存为1.max
3.为了能把max文件导出为.x文件,需要给3dsmax添加插件,把这个文件解压,拷贝到
4.把max文件导出为.x文件
5.导出的文件,拷贝到项目文件文件夹下
6.代码相应位置X文件替换
源代码
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")
#include "d3dUtility.h"
#include <fstream>
#include <vector>
//
// Globals
//
IDirect3DDevice9* Device = 0;
const int Width = 640;
const int Height = 480;
//第1步 网格文件指针,材质,贴图
//ID3DXMesh* Mesh = 0;
//std::vector<D3DMATERIAL9> Mtrls(0);
//std::vector<IDirect3DTexture9*> Textures(0);
LPD3DXMESH Mesh = NULL; // 网格对象
D3DMATERIAL9* Materials = NULL; // 网格的材质信息
LPDIRECT3DTEXTURE9* Textures = NULL; // 网格的纹理信息
DWORD NumMtrls = 0; // 材质的数目
//
// Framework functions
//
bool Setup()
{
HRESULT hr = 0;
ID3DXBuffer* adjBuffer = 0;//保存每个三角形的邻接信息
ID3DXBuffer* mtrlBuffer = 0;//保存材质
//DWORD numMtrls = 0;//保存材质数量
hr = D3DXLoadMeshFromX(
L"1.x",
//"bigship1.x",
//"car.x",
D3DXMESH_MANAGED,//指定网格文件存入,托管的内存里
Device,
&adjBuffer,//保存每个三角形的邻接信息
&mtrlBuffer,//保存材质
0,
&NumMtrls,//保存材质数量
&Mesh);
if(FAILED(hr))
{
::MessageBox(0,L"D3DXLoadMeshFromX() - Failed",0,0);
return false;
}
检查x文件中有没有材质部分,
//if(mtrlBuffer != 0 && numMtrls != 0)
//{
// D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();//有材质部分,就把它们提取出来
// for(int i=0; i<numMtrls; i++)
// {
// mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;
// Mtrls.push_back(mtrls[i].MatD3D);
// if(mtrls[i].pTextureFilename != 0)
// {
// IDirect3DTexture9* tex = 0;
// D3DXCreateTextureFromFile(Device, (LPCWSTR)mtrls[i].pTextureFilename, &tex);
// Textures.push_back(tex);
// }else{
// Textures.push_back(0);
// }
// }
//}
//d3d::Release<ID3DXBuffer*>(mtrlBuffer);
//hr = Mesh->OptimizeInplace(
// D3DXMESHOPT_ATTRSORT |
// D3DXMESHOPT_COMPACT |
// D3DXMESHOPT_VERTEXCACHE,
// (DWORD*)adjBuffer->GetBufferPointer(),
// 0,0,0);
//d3d::Release<ID3DXBuffer*>(adjBuffer);
//if(FAILED(hr))
//{
// ::MessageBox(0,L"OptimizeInplace() - FAILED",0,0);
// return false;
//}
//
//Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
//Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
//Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
// 读取材质和纹理数据
D3DXMATERIAL *pMtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); //创建一个D3DXMATERIAL结构体用于读取材质和纹理信息
Materials = new D3DMATERIAL9[NumMtrls];
Textures = new LPDIRECT3DTEXTURE9[NumMtrls];
for (DWORD i=0; i<NumMtrls; i++)
{
//获取材质,并设置一下环境光的颜色值
Materials [i] = pMtrls[i].MatD3D;
Materials [i].Ambient = Materials[i].Diffuse;
//创建一下纹理对象
Textures[i] = NULL;
D3DXCreateTextureFromFileA(Device, pMtrls[i].pTextureFilename, &Textures[i]);
}
d3d::Release<ID3DXBuffer*>(mtrlBuffer);
hr = Mesh->OptimizeInplace( //使用OptimizeInplace()进行网格优化后,Mesh 的几何信息将按照属性进行排序,这样各个子集的顶点/索引将组成连续的块
D3DXMESHOPT_ATTRSORT |
D3DXMESHOPT_COMPACT |
D3DXMESHOPT_VERTEXCACHE,
(DWORD*)adjBuffer->GetBufferPointer(),
0,0,0);
d3d::Release<ID3DXBuffer*>(adjBuffer);
//灯光
D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);
D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);
D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);
Device->SetLight(0,&light);
Device->LightEnable(0,true);
Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
Device->SetRenderState(D3DRS_SPECULARENABLE, true);
//
// Set camera.
//
D3DXVECTOR3 pos(0.0f, 10.0f, -50.0f);
D3DXVECTOR3 target(0.0f, 10.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(
&V,
&pos,
&target,
&up);
Device->SetTransform(D3DTS_VIEW, &V);
//
// Set projection matrix.
//
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI * 0.5f, // 90 - degree
(float)Width / (float)Height,
1.0f,
1000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
void Cleanup()
{
}
bool Display(float timeDelta)
{
if( Device )
{
//
// Render
//
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
Device->BeginScene();
for(int i=0; i<NumMtrls; i++)
{
Device->SetMaterial(&Materials[i]);
Device->SetTexture(0, Textures[i]);
Mesh->DrawSubset(i);
}
Device->EndScene();
Device->Present(0, 0, 0, 0);
}
return true;
}
//
// WndProc
//
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_DESTROY:
::PostQuitMessage(0);
break;
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
::DestroyWindow(hwnd);
break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
//
// WinMain
//
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE prevInstance,
PSTR cmdLine,
int showCmd)
{
if(!d3d::InitD3D(hinstance,
Width, Height, true, D3DDEVTYPE_HAL, &Device))
{
::MessageBox(0, L"InitD3D() - FAILED", 0, 0);
return 0;
}
if(!Setup())
{
::MessageBox(0, L"Setup() - FAILED", 0, 0);
return 0;
}
d3d::EnterMsgLoop( Display );
Cleanup();
Device->Release();
return 0;
}
注意点:这个源码是在Unicode下编码,所以有了相应修改
1.4 通过assimp加载模型
Assimp是Open Asset Import Library(开放的资产导入库)的缩写。Assimp能够导入很多种不同的模型文件格式(并也能够导出部分的格式),它会将所有的模型数据加载至Assimp的通用数据结构中。当Assimp加载完模型之后,我们就能够从Assimp的数据结构中提取我们所需的所有数据了。由于Assimp的数据结构保持不变,不论导入的是什么种类的文件格式,它都能够将我们从这些不同的文件格式中抽象出来,用同一种方式访问我们需要的数据。
Assimp模型加载库下载、编译、配置全过程参考下面网址
https://blog.csdn.net/derbi123123/article/details/105783048/
assimp3.1.1源码下载后,在cmake下为vs2010编译好lib和dll文件
生成成功后在你的build文件的code文件夹下会有Release文件夹,里面有.dll文件与.lib文件:
最终的配置和链接
终于弄完了,最后只需要配置和链接:
-
把上面文件夹中的lib文件拷贝到vs安装目录的lib文件夹下,并在解决方案中链接它(在链接器的输入中的附加依赖项中输入assimp.lib)。
-
且记得把Assimp的头文件也复制到你的include目录中(头文件可以在从Assimp中的include目录里找到)。
-
还有把dll文件放到C:\Windows\System32和C:\Windows\SysWOW64中即可。