DirectX简单的FBX文件加载(网格MESH)
FBX文件加载需要用到FBX SDK,有关配置可以自己上网或者查看官方文档进行设置(参见)
http://help.autodesk.com/view/FBX/2019/ENU/添加链接描述
这里只关注FBX文件中MESH的读取(也只是读取每个顶点的坐标而已,不进行坐标变换),十分的简单。由于FBX文件是按照节点组成的树形结构,所以这里的读取方法只能读取深度遍历下第一个mesh类型的节点。不过没有关系,可以用Blender把FBX文件的结构进行重塑(比如将mesh合并,调整左右手坐标系等),关键是原理。。。。
1.FBX初始化
先进行必要的FBX初始化然后导入
注意1:FBX不支持中文路径,Blender建模的时候节点命名也不要是中文,不然会乱码。
注意2:FBX网格基本图元有很多,四边形,三角形,五边形……,但是DirectX要三角形,所以要三角化。创建一个FbxGeometryConverter对象对整个场景进行三角化
FbxManager* m_pSdkManager;
FbxIOSettings* m_pios;
FbxImporter* m_pImporter;
m_pSdkManager=FbxManager::Create();
m_pios=FbxIOSettings::Create(m_pSdkManager,IOSROOT);
m_pSdkManager->SetIOSettings(m_pios);
m_pImporter=FbxImporter::Create(m_pSdkManager,"");
//开始导入我们需要加载的文件,这里的_filePath就是文件路径,注意FBX不支持中文路径
bool ImportStatus=m_pImporter->Initialize(_filePath,-1,m_pSdkManager->GetIOSettings());
if(!ImportStatus) return ImportStatus;
//获得根节点
FbxScene* pScene=FbxScene::Create(m_pSdkManager,"myScene");
m_pImporter->Import(pScene);
FbxNode* pRootNode=pScene->GetRootNode();
//三角化所有数据
FbxGeometryConverter converter(m_pSdkManager);
converter.Triangulate(pScene,true);
//遍历节点
ProcessNode(pRootNode);
2.ProcessNode
该函数实现了节点的遍历,传入根节点即可
FbxNodeAttribute::EType可以查看文档,发现除了FbxMesh我们需要其他暂时用不上
void FBX::ProcessNode(FbxNode* _pFbxNode){
FbxNodeAttribute::EType attributeType;
if(_pFbxNode->GetNodeAttribute()!=NULL){
attributeType=_pFbxNode->GetNodeAttribute()->GetAttributeType();
switch(attributeType){
case FbxNodeAttribute::EType::eMesh:
//处理网格数据
ProcessMesh(_pFbxNode);
break;
}
}
for(int i=0;i<=_pFbxNode->GetChildCount()-1;++i)
ProcessNode(_pFbxNode->GetChild(i));
}
3.ProcessMesh
要点1:从FbxMesh中获得顶点数组
要点2:从FbxVector4中得到我们需要的x,y,z
要点3:得到索引数组int ctrlPointIndex=pMesh->GetPolygonVertex(i,j)
这里的含义是从第i个三角形中获得第j个顶点的索引
void FBX::ProcessMesh(FbxNode* _pFbxNode){
if(flag!=true) return; //这里的flag是当前是否遍历到过一个MESH,如果有就不遍历了,因为懒
flag=false;//遍历过了,调整flag
FbxMesh* pMesh=_pFbxNode->GetMesh();
if(!pMesh) return;
FBX_VERTEX* pVertexArray=NULL;//FBX_VERTEX是我定义的顶点格式,只有x,y,z坐标
//顶点的存储
int ctrlcount=pMesh->GetControlPointsCount();
m_VertexCount=ctrlcount;//就是顶点个数
pVertexArray=new FBX_VERTEX[ctrlcount];
D3DXVECTOR3 vertex;
FbxVector4* pCtrlPoint=pMesh->GetControlPoints();//这里的控制点数组pCtrlPoint其实就是DirectX里顶点的意思,就是顶点数组
for(unsigned int i=0;i<=ctrlcount-1;i++){
vertex.x=pCtrlPoint[i].mData[0];//这里得到控制点(顶点)的x,y,z
vertex.y=pCtrlPoint[i].mData[1];//这段数据的获得找了好多资料才知道的
vertex.z=pCtrlPoint[i].mData[2];//FBX的样例真心看不懂
//接下来存入我们的顶点数组中
pVertexArray[i]=FBX_VERTEX(vertex);
}
//创建顶点缓存
HRESULT hr=m_pd3dDevice->CreateVertexBuffer(
ctrlcount*sizeof(FBX_VERTEX),0,FVF,D3DPOOL_MANAGED,&m_pVertexBuffer,0);
if(FAILED(hr)) exit(1);
//存入顶点缓存中
FBX_VERTEX* lVertexArray;
m_pVertexBuffer->Lock(0,0,(void**)&lVertexArray,0);
memcpy(lVertexArray,pVertexArray,ctrlcount*sizeof(FBX_VERTEX));
m_pVertexBuffer->Unlock();
delete [] pVertexArray;
//索引的存储,故技重施即可,但有一点需要注意
int* pIndexArray=NULL;
unsigned int triangleCount=pMesh->GetPolygonCount();//多边形图元的数量
//因为已经三角化过,所以一定是三角形了
m_TriangleCount=triangleCount;//三角形面片的数量
pIndexArray=new int[triangleCount*3];//三角形面皮的数量*3就是索引的数量
unsigned int index_count=0;
for(unsigned int i=0;i<=triangleCount-1;i++){
//这里一定是三角形了也可判断下
/*
if(pMesh->GetPolygonSize(i)!=3){return;}
*/
for(unsigned int j=0;j<=pMesh->GetPolygonSize(i)-1;j++){
int ctrlPointIndex=pMesh->GetPolygonVertex(i,j);
//这里要存入索引数组中
pIndexArray[index_count]=ctrlPointIndex;
index_count++;
}
}
//创建索引数组
hr=m_pd3dDevice->CreateIndexBuffer(
(index_count+1)*sizeof(int),0,D3DFMT_INDEX32,D3DPOOL_MANAGED,&m_pIndexBuffer,0);
if(FAILED(hr)) exit(1);
int* lIndexArray;
m_pIndexBuffer->Lock(0,0,(void**)&lIndexArray,0);
memcpy(lIndexArray,pIndexArray,(index_count+1)*sizeof(int));
m_pIndexBuffer->Unlock();
delete [] pIndexArray;
}
4.Draw
开始绘制
void FBX::Draw(D3DXMATRIX _mat)
{
//_mat暂时不知道干什么,但是有用,可以以后指定模型的位置
//m_pd3dDevice->BeginScene();
m_pd3dDevice->SetStreamSource(0,m_pVertexBuffer,0,sizeof(FBX_VERTEX));
m_pd3dDevice->SetIndices(m_pIndexBuffer);
m_pd3dDevice->SetFVF(FVF);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,m_VertexCount,0,m_TriangleCount);
//m_pd3dDevice->EndScene();
}
这里只展示了部分代码,我将这些东西写了一个FBX类,用来导入FBX文件
实验怎么导入FBX网格文件,以龙书的Camera例程为主体,可以遨游观看FBX文件
效果图:
1.FBX SDK中的humanoid.fbx,这里倒了是因为这个fbx用右手坐标系,而DirectX用左手。因为可以用Blender调整这里也不管了。话说为什么高考数学要用右手坐标系做立体几何???DirectX习惯了表示只会左手坐标系,到头来答案错了一分莫得。。。。
2.自己用Blender做的一个简单模型(还带有动画,等以后解析完了FBX的动画在看看)