测试过irrlicht中ms3d模型的朋友可能发现了这样的现象,如果ms3d模型只有一个贴图,则无论贴图文件放到和demo可执行程序同一目录下或者调用setMaterialTexture()函数都可以让模型正常被正常渲染,而当模型拥有两个或以上贴图时,则只有贴图和可执行程序在同一目录被自动加载时才能正确渲染,而用setMaterialTexture(0,。。。),setMaterialTexture(1,。。。)时似乎只有第一个贴图起作用。仔细查看引擎的代码发现,这不是偶然的现象,也可以算是引擎对ms3d模型支持的一个bug吧。在说到具体的解决方案之前,我们先来说一下ms3d模型中组的概念。“组”顾名思义应该是拥有一些共同属性的事物集合了。在ms3d中,一个组内的三角形就拥有同一个贴图文件。在引擎装载ms3d模型数据时,已经记下了组对应的贴图文件名,因此自动贴图不会出错。而在用setMaterialTexture函数指定时却并没有指定是哪个组的贴图,因此就会出现只有一个贴图起效果的现像,其实从代码中可以看出,它是遍历了所有组,但都用了setMaterialTexture(0,...)指定的这一个贴图。
好了,知道原因后,我们大概就可以想到解决办法了。就是在setMaterialTexture时也指定是哪个组。对就是这样。我们提供了另外两个针对MS3D的setMaterialTexture函数,分别是:
void CAnimatedMeshSceneNode::setMS3DMaterialTexture(const c8 * groupName,s32 textureLayer, video::ITexture* texture)
{
if (textureLayer<0 || textureLayer>= video::MATERIAL_MAX_TEXTURES)
return;
// 根据组名得到MeshBuffer
IMesh * pMesh = Mesh->getMesh(0,0);
for(s32 i = 0; i<pMesh->getMeshBufferCount();i++)
{
IMeshBuffer* pMeshBuf = pMesh->getMeshBuffer(i);
if(strcmp(pMeshBuf->getGroupName(),groupName) == 0){
irr::video::SMaterial & mat = pMeshBuf->getMaterial();
mat.Textures[textureLayer] = texture;
Materials[i].Texture1 = texture;
break;
}
}
}
void CAnimatedMeshSceneNode::setMS3DMaterialTexture(s32 groupIndex,s32 textureLayer, video::ITexture* texture)
{
if (textureLayer<0 || textureLayer>= video::MATERIAL_MAX_TEXTURES)
return;
// 根据组名得到MeshBuffer
IMesh * pMesh = Mesh->getMesh(0,0);
if(groupIndex < 0 || groupIndex > pMesh->getMeshBufferCount())
return;
IMeshBuffer* pMeshBuf = pMesh->getMeshBuffer(groupIndex);
// yfxu
irr::video::SMaterial & mat = pMeshBuf->getMaterial();
mat.Textures[textureLayer] = texture;
if(textureLayer == 0) mat.Texture1 = texture;
Materials[groupIndex].Texture1 = texture;
}
一个是根据组名设贴图,一个是根据组索引设贴图。
值得一起的是 引擎在载如ms3d模型数据在取组名时也有一点问题,原来的代码如下:
for (i=0; i<numGroups; ++i)
{
Groups.push_back(SGroup());
SGroup& grp = Groups.getLast();
// 组名称
grp.Name = (const c8*)pPt;
。。。
参考ms3d的文件格式可知改为:
grp.Name = (const c8*)(pPt+1);
才能正确取到组名。
到此为止,加上动画模型旋转bug,和无效帧问题的解决。irrlicht对ms3d模型的支持基本就完美了。
下图中的美女,身体和头发是分开的贴图: