5. 加载材质
Material是一个模型渲染时必不可少的部分,当然,这些信息也被存到了FBX之中(甚至各种贴图等也可以直接内嵌到FBX内部),就需要从FBX中加载这些信息以完成带有材质的渲染。材质的加载可以与Mesh的加载相结合来完成,但更好的方法是独立进行,这样各模块间的关系更清晰,但这就需要一个额外的操作,那就是关联Mesh与Material。FBX中的材质对象包含了丰富的信息,比如最常规的从Max中可以看到那些材质属性,如ambient、diffuse、specular的color和texture;shininess、opacity值等,更高级一点的属性诸如Effect的参数、源文件等都可以保存。它是尽可能保证从建模工具中导出时不丢失地保存材质信息,但我们在使用时却可以有选择地读取。
5.1 关联Mesh与材质
对于Material与Mesh独立加载的系统而言,首先需要读取相关的信息将两者关联起来,这些信息其实对也都存储在KFbxMesh之内(属于几何信息的一部分吧)。每个带有材质的Mesh结点上都会包含有一个类型为KFbxGeometryElementMaterial的结点(若不含有材质则该结点为空),该结点中记录了Mesh中的多边形(这里全部为三角形)与每个材质的对应关系,读取该结点中的信息建立Mesh与Material之间的连接关系,代码如下:
void ConnectMaterialToMesh(KFbxMesh* pMesh , int triangleCount , int* pTriangleMtlIndex)
{
// Get the material index list of current mesh
KFbxLayerElementArrayTemplate<int>* pMaterialIndices;
KFbxGeometryElement::EMappingMode materialMappingMode = KFbxGeometryElement::eNONE;
if(pMesh->GetElementMaterial())
{
pMaterialIndices = &pMesh->GetElementMaterial()->GetIndexArray();
materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();
if(pMaterialIndices)
{
switch(materialMappingMode)
{
case KFbxGeometryElement::eBY_POLYGON:
{
if(pMaterialIndices->GetCount() == triangleCount)
{
for(int triangleIndex = 0 ; triangleIndex < triangleCount ; ++triangleIndex)
{
int materialIndex = pMaterialIndices->GetAt(triangleIndex);
pTriangleMtlIndex[triangleIndex] = materialIndex;
}
}
}
break;
case KFbxGeometryElement::eALL_SAME:
{
int lMaterialIndex = pMaterialIndices->GetAt(0);
for(int triangleIndex = 0 ; triangleIndex < triangleCount ; ++triangleIndex)
{
int materialIndex = pMaterialIndices->GetAt(triangleIndex);
pTriangleMtlIndex[triangleIndex] = materialIndex;
}
}
}
}
}
}
其中上triangleCount即为从pMesh中读取得到的三角形的数量,pTriangleMtlIndex是一个长度为triangleCount的数组,主要用来存储读取到的三角形对应的材质索引。注意:这里考虑的情况是对于一个三角形只对应一个材质,而一般情况下也是这样(如果是对应多个材质的话需要些许修改此处的代码)。完成Mesh的索引读取之后即可以将pTriangleMtlIndex中的值以合适的方式转储到对应的三角形列表中(或以其它的方式对应)以便在渲染时使用。
5.2 普通材质
FBX中实际存储材质信息的位置是每个Mesh中对应的一个类型为KFbxSurfaceMaterial的结点,其里边存储了普通材质的典型信息,主要包括以下属性(有一些没有列出):