这两天在做 3D蒙皮动画时遇到些问题,折腾了一天半,嗨!很郁闷啊!我要大叫来发泄一下。
本来打算用D3D设备直接设置世界坐标矩阵来实现动画的,但发现有一个问题,当我不使用D3DXEFFECT来设置渲染效果的时候就可以正常显示动画;当我使用它来设置渲染效果的时候,动画就没了。我想可能是用D3DXEFFECT来设置渲染效果的时候把D3D设备的 SetTransform功能屏蔽掉了(其实我不理解这个渲染过程^_^)。
下面说一下加载和渲染蒙皮动画的大概流程吧。
首先继承2个结构:D3DXFRAME、D3DMESHCONTAINER 和一个接口:ID3DXAllocateHierarchy。
//------------------------------------------------------------
//说明:框架
//------------------------------------------------------------
struct GFrame : public D3DXFRAME
{
D3DXMATRIXA16 CombinedTransformationMatrix; //最终变换矩阵
};
//------------------------------------------------------------
//说明:网格容器
//------------------------------------------------------------
struct GMeshContainer : public D3DXMESHCONTAINER
{
LPDIRECT3DTEXTURE9 * _ppTexs; //纹理列表
LPD3DXMESH _pOrigMesh; //原mesh
DWORD _dwNumAttrGroups; //属性组个数
DWORD _dwMaxNumInfl; //一个面最多受多少骨骼影响
DWORD _dwNumPaletteEntries; //样色个数
LPD3DXBUFFER _pBoneCombBuf; //邻接矩阵列表
D3DXMATRIX** _ppBoneMatrixPtr; //骨骼矩阵列表
D3DXMATRIX* _pBoneOffsetMatrices; //骨骼矩阵引用
DWORD _iAttrSW; //用户 GenerateSkinnedMesh
};
//------------------------------------------------------------
//说明:封装网格的创建类
//------------------------------------------------------------
class GAllocateHierarchy : public ID3DXAllocateHierarchy
{
public:
// 下面4个方法是对父类的实现
STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame);
STDMETHOD(CreateMeshContainer)(THIS_
LPCSTR Name,
CONST D3DXMESHDATA *pMeshData,
CONST D3DXMATERIAL *pMaterials,
CONST D3DXEFFECTINSTANCE *pEffectInstances,
DWORD NumMaterials,
CONST DWORD *pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER *ppNewMeshContainer);
STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);
STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase);
};
//----------------------------------------------------
// 创建框架
//----------------------------------------------------
HRESULT GAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME * ppNewFrame)
{
HRESULT hr;
GFrame * pFrame;
pFrame = new GFrame();
*ppNewFrame = NULL;
if( !pFrame)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
//复制框架名称
hr = HeapCopy( Name, &pFrame->Name);
if( FAILED( hr) )
goto e_Exit;
//初始化其它属性
D3DXMatrixIdentity( &pFrame->TransformationMatrix);
D3DXMatrixIdentity( &pFrame->CombinedTransformationMatrix);
pFrame->pMeshContainer = NULL;
pFrame->pFrameFirstChild = NULL;
pFrame->pFrameSibling = NULL;
//复制到新框架
*ppNewFrame = pFrame;
pFrame = NULL;
e_Exit:
delete pFrame;
return hr;
}
//----------------------------------------------------
// 创建Mesh
//----------------------------------------------------
HRESULT GAllocateHierarchy::CreateMeshContainer(
LPCSTR Name,
CONST D3DXMESHDATA * pMeshData,
CONST D3DXMATERIAL * pMaterials,
CONST D3DXEFFECTINSTANCE * pEffectInst,
DWORD dwNumMaterials,
CONST DWORD * pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER * ppNewMeshContainer)
{
HRESULT hr;
GMeshContainer * pMeshContainer = NULL;
UINT iNumFaces;
LPDIRECT3DDEVICE9 pDev = NULL;
LPD3DXMESH pMesh = NULL;
*ppNewMeshContainer = NULL;
//----------------------------
//验证异常
if( pMeshData->Type != D3DXMESHTYPE_MESH)
{
hr = E_FAIL;
goto e_Exit;
}
pMesh = pMeshData->pMesh;
if( pMesh->GetFVF() == 0)
{
hr = E_FAIL;
goto e_Exit;
}
pMeshContainer = new GMeshContainer();
if( pMeshContainer == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
//-------------------------
//初始化 pMeshContainer ,复制名字, 获取pDev , 获取面信息
memset( pMeshContainer, 0, sizeof( GMeshContainer));
hr = HeapCopy( Name, &pMeshContainer->Name);
if( FAILED( hr))
goto e_Exit;
pMesh->GetDevice( & pDev);
iNumFaces = pMesh->GetNumFaces();
//--------------------------
//判断是否要处理法向量,并复制 Mesh
if( !(pMesh->GetFVF() & D3DFVF_NORMAL) ) //如果没有法向量,则添加法向量
{
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
hr = pMesh->CloneMeshFVF( pMesh->GetOptions(),
pMesh->GetFVF() | D3DFVF_NORMAL,
pDev,
&pMeshContainer->MeshData.pMesh);
if( FAILED( hr))
goto e_Exit;
pMesh = pMeshContainer->MeshData.pMesh;
D3DXComputeNormals( pMesh, NULL);
}
else //如果有法向量,则直接复制 Mesh
{
pMeshContainer->MeshData.pMesh = pMesh;
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
pMesh->AddRef();
}
//----------------------------
// 获取材质个数,并初始化材质、纹理、邻接矩阵信息
pMeshContainer->NumMaterials = max( 1, dwNumMaterials);
pMeshContainer->pMaterials = new D3DXMATERIAL[ pMeshContainer->NumMaterials ];
pMeshContainer->_ppTexs = new LPDIRECT3DTEXTURE9[ pMeshContainer->NumMaterials ];
pMeshContainer->pAdjacency = new DWORD[ iNumFaces * 3];
if( pMeshContainer->pMaterials == NULL || pMeshContainer->pAdjacency == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
memcpy( pMeshContainer->pAdjacency, pAdjacency, sizeof( DWORD) * iNumFaces * 3);
memset( pMeshContainer->_ppTexs, 0, sizeof( LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials);
//--------------------------------
// 复制材质,创建纹理
if( dwNumMaterials > 0) //如果有材质,则复制材质
{
memcpy( pMeshContainer->pMaterials, pMaterials, sizeof( D3DXMATERIAL) * dwNumMaterials);
for( UINT i = 0; i < dwNumMaterials; ++i)
{
//如果有纹理则加载纹理
if( pMeshContainer->pMaterials[ i ].pTextureFilename != NULL)
{
LPSTR pFileName = pMeshContainer->pMaterials[ i ].pTextureFilename;
if( FAILED( D3DXCreateTextureFromFileA( pDev, pFileName, &pMeshContainer->_ppTexs[ i ])) )
pMeshContainer->_ppTexs[ i ] = NULL;
//清除纹理文件名
pMeshContainer->pMaterials[ i ].pTextureFilename = NULL;
}
}
}
else //如果没有材质则初始化默认值
{
pMeshContainer->pMaterials[ 0 ].pTextureFilename = NULL;
memset( &pMeshContainer->pMaterials[ 0 ].MatD3D, 0, sizeof( D3DMATERIAL9));
pMeshContainer->pMaterials[ 0 ].MatD3D.Diffuse.r = 0.5f;
pMeshContainer->pMaterials[ 0 ].MatD3D.Diffuse.g = 0.5f;
pMeshContainer->pMaterials[ 0 ].MatD3D.Diffuse.b = 0.5f;
pMeshContainer->pMaterials[ 0 ].MatD3D.Specular = pMeshContainer->pMaterials[ 0 ].MatD3D.Diffuse;
}
//----------------------------
//如果有 Skin 则创建 Skin,并创建拷贝它的骨骼矩阵信息
if( pSkinInfo != NULL)
{
pMeshContainer->pSkinInfo = pSkinInfo;
pSkinInfo->AddRef();
pMeshContainer->_pOrigMesh = pMesh;
pMesh->AddRef();
UINT iTotalBones = pSkinInfo->GetNumBones();
pMeshContainer->_pBoneOffsetMatrices = new D3DXMATRIX[ iTotalBones ];
if( pMeshContainer->_pBoneOffsetMatrices == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
for( UINT i = 0; i < iTotalBones; ++i)
{
pMeshContainer->_pBoneOffsetMatrices[ i ] = *(pSkinInfo->GetBoneOffsetMatrix( i ));
}
hr = GenerateSkinnedMesh( pDev, pMeshContainer);
if( FAILED( hr ) )
goto e_Exit;
}
//--------------------------
// 赋值 MeshContainer
*ppNewMeshContainer = pMeshContainer;
pMeshContainer = NULL;
e_Exit:
SAFE_RELEASE( pDev);
if( pMeshContainer != NULL)
DestroyMeshContainer( pMeshContainer);
return hr;
}
//----------------------------------------------------
// 销毁 Frame
//----------------------------------------------------
HRESULT GAllocateHierarchy::DestroyFrame( LPD3DXFRAME pFrameToFree)
{
SAFE_DELETE_ARRAY( pFrameToFree->Name);
SAFE_DELETE( pFrameToFree);
return S_OK;
}
//----------------------------------------------------
// 销毁 MeshContainer
//----------------------------------------------------
HRESULT GAllocateHierarchy::DestroyMeshContainer( LPD3DXMESHCONTAINER pMeshContainerToFree)
{
GMeshContainer * pMeshContainer = ( GMeshContainer *) pMeshContainerToFree;
SAFE_DELETE_ARRAY( pMeshContainer->Name);
SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );
SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );
SAFE_DELETE_ARRAY( pMeshContainer->_pBoneOffsetMatrices);
if( pMeshContainer->_ppTexs != NULL)
{
for( UINT i = 0; i < pMeshContainer->NumMaterials; ++i)
{
SAFE_RELEASE( pMeshContainer->_ppTexs[ i ]);
}
}
SAFE_DELETE_ARRAY( pMeshContainer->_ppTexs );
SAFE_DELETE_ARRAY( pMeshContainer->_ppBoneMatrixPtr);
SAFE_RELEASE( pMeshContainer->_pBoneCombBuf);
SAFE_RELEASE( pMeshContainer->MeshData.pMesh);
SAFE_RELEASE( pMeshContainer->pSkinInfo );
SAFE_RELEASE( pMeshContainer->_pOrigMesh);
SAFE_DELETE( pMeshContainer );
return S_OK;
}
//----------------------------------------------------
// 为 MeshContainer生成纹理
//----------------------------------------------------
// pNumBoneMatrixMax 为最大受骨骼影响的数目
HRESULT GAllocateHierarchy::GenerateSkinnedMesh( IDirect3DDevice9 * pDev, GMeshContainer * pMeshContainer)
{
HRESULT hr = S_OK;
D3DCAPS9 caps;
pDev->GetDeviceCaps( & caps);
if( pMeshContainer->pSkinInfo == NULL)
return hr;
SAFE_RELEASE( pMeshContainer->MeshData.pMesh);
SAFE_RELEASE( pMeshContainer->_pBoneCombBuf );
UINT iMaxMatrices = 26;
pMeshContainer->_dwNumPaletteEntries = min( iMaxMatrices, pMeshContainer->pSkinInfo->GetNumBones());
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
Flags |= D3DXMESH_MANAGED;
SAFE_RELEASE( pMeshContainer->MeshData.pMesh);
hr = pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh(
pMeshContainer->_pOrigMesh,
Flags,
pMeshContainer->_dwNumPaletteEntries,
pMeshContainer->pAdjacency,
NULL, NULL, NULL,
& pMeshContainer->_dwMaxNumInfl,
& pMeshContainer->_dwNumAttrGroups,
& pMeshContainer->_pBoneCombBuf,
& pMeshContainer->MeshData.pMesh );
if( FAILED( hr ) )
goto e_Exit;
DWORD NewFVF = ( pMeshContainer->MeshData.pMesh->GetFVF() & D3DFVF_POSITION_MASK) | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_LASTBETA_UBYTE4;
if( NewFVF != pMeshContainer->MeshData.pMesh->GetFVF() )
{
LPD3DXMESH pMesh;
hr = pMeshContainer->MeshData.pMesh->CloneMeshFVF( pMeshContainer->MeshData.pMesh->GetOptions(), NewFVF, pDev, &pMesh);
if( ! FAILED( hr ) )
{
pMeshContainer->MeshData.pMesh->Release();
pMeshContainer->MeshData.pMesh = pMesh;
pMesh = NULL;
}
}
D3DVERTEXELEMENT9 pDecl[ MAX_FVF_DECL_SIZE];
LPD3DVERTEXELEMENT9 pDeclCur;
hr = pMeshContainer->MeshData.pMesh->GetDeclaration( pDecl);
if( FAILED( hr ) )
goto e_Exit;
pDeclCur = pDecl;
while( pDeclCur->Stream != 0xff)
{
if( (pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES) && ( pDeclCur->UsageIndex == 0 ) )
pDeclCur->Type = D3DDECLTYPE_D3DCOLOR;
pDeclCur++;
}
hr = pMeshContainer->MeshData.pMesh->UpdateSemantics( pDecl);
if( FAILED( hr ) )
goto e_Exit;
if( m_iNumBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones() )
{
m_iNumBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones();
SAFE_DELETE_ARRAY( m_pBoneMatrices);
m_pBoneMatrices = new D3DXMATRIXA16[ m_iNumBoneMatricesMax ];
if( *m_pBoneMatrices == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
}
//}
e_Exit:
return hr;
}
创建两个全局指针:
LPD3DXFRAME g_pFrameRoot = NULL; //根Frame
ID3DXAnimationController* g_pAnimCtl = NULL; //动画控制类
接着在初始化的地方(如果使用DXUT,则可以在OnCreateDevice中)调用 D3DXLoadMeshHierarchyFromX 来加载x文件。
GAllocateHierarchy ah;
D3DXLoadMeshHierarchyFromX( strXFileName, D3DXMESH_MANAGED, pDev,
& ah, NULL, & g_pFrameRoot, &g_pAnimCtl );
SetupBoneMatrixPointers( g_pFrameRoot, g_pFrameRoot); //建立矩阵指针
D3DXFrameCalculateBoundingSphere( g_pFrameRoot, & g_vObjCenter, g_fObjRadius ); //获取模型边界球
//------------------------------------------------------------
//desc:为框架建立骨骼矩阵
//param: pFrame 当前框架
//param: pFrameRoot 根框架
//return: 操作是否成功
//------------------------------------------------------------
HRESULT XFileObjBuilder::SetupBoneMatrixPointers(LPD3DXFRAME pFrame, LPD3DXFRAME pFrameRoot)
{
HRESULT hr;
if( pFrame->pMeshContainer != NULL)
{
hr = SetupBoneMatrixPointersOnMesh( pFrame->pMeshContainer, pFrameRoot);
if( FAILED( hr ) )
return hr;
}
if( pFrame->pFrameSibling != NULL)
{
hr = SetupBoneMatrixPointers( pFrame->pFrameSibling, pFrameRoot);
if( FAILED( hr ) )
return hr;
}
if( pFrame->pFrameFirstChild != NULL)
{
hr = SetupBoneMatrixPointers( pFrame->pFrameFirstChild, pFrameRoot);
if( FAILED( hr ) )
return hr;
}
return S_OK;
}
//------------------------------------------------------------
//desc: 为网格容器创建骨骼矩阵
//param: pMeshContainer 当前容器
//param: pFrameRoot 根框架
//return: 操作是否成功
//------------------------------------------------------------
HRESULT XFileObjBuilder::SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameRoot)
{
GFrame * pFrame;
GMeshContainer * pMeshContainer = (GMeshContainer *) pMeshContainerBase;
if( pMeshContainer->pSkinInfo != NULL)
{
UINT iTotalBones = pMeshContainer->pSkinInfo->GetNumBones();
pMeshContainer->_ppBoneMatrixPtr = new D3DXMATRIX * [ iTotalBones ];
if( pMeshContainer->_ppBoneMatrixPtr == NULL)
return E_OUTOFMEMORY;
for( UINT i = 0; i < iTotalBones; ++i)
{
pFrame = (GFrame *) D3DXFrameFind( pFrameRoot, pMeshContainer->pSkinInfo->GetBoneName( i));
if( NULL == pFrame)
return E_FAIL;
pMeshContainer->_ppBoneMatrixPtr[ i ] = & pFrame->CombinedTransformationMatrix;
}
}
return S_OK;
}
接着在更新信息的地方(如果使用DXUT,则可以在OnFrameMove中添加)添加以下代码:
UpdateFrameMatrices( g_pFrameRoot, &matWorld); //更新骨骼矩阵(其中 matWorld 可以包含模型的平移、缩放、旋转信息)
if( g_pAnimCtl != NULL)
g_pAnimCtl->AdvanceTime( fElapsedTime, NULL); //更新动画信息就靠它了
UpdateFrameMatrices 的实现如下:
//------------------------------------------------------------
//desc: 更新框架矩阵
//param: pFrameBase 当前框架
//param: pParentMatrix 父框架矩阵
//------------------------------------------------------------
void G3DObjEntity::UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix)
{
assert( pFrameBase != NULL);
assert( pParentMatrix != NULL);
GFrame * pFrame = (GFrame *) pFrameBase;
if( pParentMatrix != NULL)
D3DXMatrixMultiply( &pFrame->CombinedTransformationMatrix, &pFrame->TransformationMatrix, pParentMatrix);
else
pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;
if( pFrame->pFrameSibling != NULL)
UpdateFrameMatrices( pFrame->pFrameSibling, pParentMatrix);
if( pFrame->pFrameFirstChild != NULL)
UpdateFrameMatrices( pFrame->pFrameFirstChild, & pFrame->CombinedTransformationMatrix);
}
最后在渲染的地方(如果使用DXUT,则在 OnFrameRender中)调用:
DrawFrame( pDev, g_pFrameRoot);
DrawFrame 的实现如下:
//------------------------------------------------------------
//desc: 画框架
//param: matView 视口矩阵
//param: pDev 设备
//param: pFrame 框架
//------------------------------------------------------------
void G3DObjEntity::DrawFrame(IDirect3DDevice9 * pDev, LPD3DXFRAME pFrame)
{
LPD3DXMESHCONTAINER pMeshContainer = pFrame->pMeshContainer;
while( pMeshContainer != NULL)
{
DrawMeshContainer( pDev, pMeshContainer, pFrame);
pMeshContainer = pMeshContainer->pNextMeshContainer;
}
if( pFrame->pFrameSibling != NULL)
DrawFrame( pDev, pFrame->pFrameSibling);
if( pFrame->pFrameFirstChild != NULL)
DrawFrame( pDev, pFrame->pFrameFirstChild);
}
//------------------------------------------------------------
//desc: 画网格
//param: matView 视口矩阵
//param: pDev 设备
//param: pMeshContainerBase 网格指针
//param: pFrameBase 框架指针
//------------------------------------------------------------
void G3DObjEntity::DrawMeshContainer( IDirect3DDevice9 * pDev, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase)
{
HRESULT hr;
GFrame * pFrame = ( GFrame *) pFrameBase;
GMeshContainer * pMeshContainer = ( GMeshContainer *) pMeshContainerBase;
UINT iMaterial;
UINT iNumBlend;
UINT iAttr;
DWORD iAttrIdPrev;
LPD3DXBONECOMBINATION pBoneComb;
UINT iMatrixIndex;
UINT iPaletteEntry;
D3DXMATRIXA16 matTemp;
LPD3DXEFFECT pEffect = NULL;
if( m_pObjInfo != NULL && m_pObjInfo->GetEffectProxy() != NULL)
{
pEffect = m_pObjInfo->GetEffectProxy()->GetEffect();
}
D3DCAPS9 caps;
pDev->GetDeviceCaps( & caps);
if( pMeshContainer->pSkinInfo != NULL) //如果有蒙皮信息,则用HLSL处理蒙皮动画
{
D3DXMATRIX matView = * GlobalState::GetInstance()->GetCamera()->GetViewMatrix(); //这里使用DXUT 提供的摄像机
pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->_pBoneCombBuf->GetBufferPointer());
for( iAttr = 0; iAttr < pMeshContainer->_dwNumAttrGroups; ++iAttr)
{
for( iPaletteEntry = 0; iPaletteEntry < pMeshContainer->_dwNumPaletteEntries; ++iPaletteEntry)
{
iMatrixIndex = pBoneComb[ iAttr].BoneId[ iPaletteEntry];
if( iMatrixIndex != UINT_MAX )
{
D3DXMatrixMultiply( & m_pObjInfo->m_pBoneMatrices[ iPaletteEntry], & pMeshContainer->_pBoneOffsetMatrices[ iMatrixIndex ], pMeshContainer->_ppBoneMatrixPtr[ iMatrixIndex ]);
}
}
//把骨骼矩阵信息添加到 D3DXEFFECT 中
V( pEffect->SetMatrixArray( "amPalette", m_pObjInfo->m_pBoneMatrices, pMeshContainer->_dwNumPaletteEntries) );
D3DXCOLOR color1( pMeshContainer->pMaterials[ pBoneComb[iAttr].AttribId].MatD3D.Ambient);
D3DXCOLOR color2(0.25, 0.25, 0.25, 1.0);
D3DXCOLOR ambEmm;
D3DXColorModulate( &ambEmm, &color1, &color2);
ambEmm += D3DXCOLOR( pMeshContainer->pMaterials[ pBoneComb[iAttr].AttribId].MatD3D.Emissive);
//把材质信息添加到D3DXEFFECT中
V( pEffect->SetVector("g_materialDiffuse", (D3DXVECTOR4*) &(pMeshContainer->pMaterials[pBoneComb[iAttr].AttribId].MatD3D.Diffuse)) );
V( pEffect->SetVector("g_materialAmbient", (D3DXVECTOR4*) & ambEmm) );
V( pDev->SetTexture( 0, pMeshContainer->_ppTexs[ pBoneComb[iAttr].AttribId] ) );
V( pEffect->SetInt( "g_curNumBones", pMeshContainer->_dwMaxNumInfl - 1) );
UINT numPasses;
V( pEffect->Begin( &numPasses, D3DXFX_DONOTSAVESTATE) );
for( UINT iPass = 0; iPass < numPasses; ++iPass)
{
V( pEffect->BeginPass( iPass));
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttr));
V( pEffect->EndPass() );
}
V( pEffect->End() );
V( pDev->SetVertexShader( NULL) );
}
}
else //如果没有skin ,则直接设置材质
{
V( pDev->SetTransform( D3DTS_WORLD, &pFrame->CombinedTransformationMatrix ) );
for( iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; ++iMaterial)
{
V( pDev->SetMaterial( &pMeshContainer->pMaterials[ iMaterial ].MatD3D) );
V( pDev->SetTexture( 0, pMeshContainer->_ppTexs[ iMaterial ] ) );
V( pMeshContainer->MeshData.pMesh->DrawSubset( iMaterial) );
}
}
}
到此为止就可以实现加载和渲染动画了,这个实现的过程也有点复杂,一不小心搞错了某个地方,可能折腾半天都找不出原因。