📄 skinmesh.cpp
字号:
{
CAllocateHierarchy Alloc(this);
D3DXFrameDestroy(m_pFrameRoot, &Alloc);
SAFE_RELEASE(m_pAnimController);
}
//----------------------------------------------------------------------------
//Summ: 从.x文件加载模型
//Desc: 从.x文件加载模型
//Para:
// strFileName:文件名
//----------------------------------------------------------------------------
HRESULT CSkinMesh::LoadFromXFile(char *strFileName)
{
HRESULT hr;
CAllocateHierarchy Alloc(this);
hr = D3DXLoadMeshHierarchyFromX(strFileName, D3DXMESH_MANAGED, m_pd3dDevice, &Alloc, NULL, &m_pFrameRoot, &m_pAnimController);
if (FAILED(hr))
return hr;
hr = SetupBoneMatrixPointers(m_pFrameRoot);
if (FAILED(hr))
return hr;
if(m_pFrameRoot)
{
D3DXMATRIX matIdentity;
D3DXMatrixIdentity(&matIdentity);
// if(m_pAnimController )
// {
// m_pAnimController->ResetTime();
// LPD3DXANIMATIONSET aSet;
// m_pAnimController->GetAnimationSet(0,&aSet);
// m_pAnimController->RegisterAnimationSet(aSet);
// }
UpdateFrameMatrices(m_pFrameRoot,&matIdentity);
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GenerateSkinnedMesh()
// Desc: Called either by CreateMeshContainer when loading a skin mesh, or when
// changing methods. This function uses the pSkinInfo of the mesh
// container to generate the desired drawable mesh and bone combination
// table.
//-----------------------------------------------------------------------------
HRESULT CSkinMesh::GenerateSkinnedMesh(D3DXMESHCONTAINER_DERIVED *pMeshContainer)
{
HRESULT hr = S_OK;
if (pMeshContainer->pSkinInfo == NULL)
return hr;
SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
// if non-indexed skinning mode selected, use ConvertToBlendedMesh to generate drawable mesh
//如果不使用索引的蒙皮动画,就把网格转换成可绘制的网格
if (m_SkinningMethod == D3DNONINDEXED)
{
hr = pMeshContainer->pSkinInfo->ConvertToBlendedMesh
(
pMeshContainer->pOrigMesh,
D3DXMESH_MANAGED|D3DXMESHOPT_VERTEXCACHE,
pMeshContainer->pAdjacency,
NULL, NULL, NULL,
&pMeshContainer->NumInfl,
&pMeshContainer->NumAttributeGroups,
&pMeshContainer->pBoneCombinationBuf,
&pMeshContainer->MeshData.pMesh
);
if (FAILED(hr))
goto e_Exit;
//如果设备只支持2个顶点混和,ConverteToBlendMesh不能近似地转换所有的网格。这时需要把网格转换成两部分,
//只使用2个矩阵部分和其他部分。前者使用设备的顶点处理,其他部分使用软件方式处理
LPD3DXBONECOMBINATION rgBoneCombinations = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
// look for any set of bone combinations that do not fit the caps
for (pMeshContainer->iAttributeSW = 0; pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups; pMeshContainer->iAttributeSW++)
{
DWORD cInfl = 0;
for (DWORD iInfl = 0; iInfl < pMeshContainer->NumInfl; iInfl++)
{
if (rgBoneCombinations[pMeshContainer->iAttributeSW].BoneId[iInfl] != UINT_MAX)
{
++cInfl;
}
}
if (cInfl > m_d3dCaps.MaxVertexBlendMatrices)
{
break;
}
}
// if there is both HW and SW, add the Software Processing flag
if (pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups)
{
LPD3DXMESH pMeshTmp;
hr = pMeshContainer->MeshData.pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|pMeshContainer->MeshData.pMesh->GetOptions(),
pMeshContainer->MeshData.pMesh->GetFVF(),
m_pd3dDevice, &pMeshTmp);
if (FAILED(hr))
{
goto e_Exit;
}
pMeshContainer->MeshData.pMesh->Release();
pMeshContainer->MeshData.pMesh = pMeshTmp;
pMeshTmp = NULL;
}
}
// if indexed skinning mode selected, use ConvertToIndexedsBlendedMesh to generate drawable mesh
else if (m_SkinningMethod == D3DINDEXED) //索引缓冲区模式的
{
DWORD NumMaxFaceInfl;
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
LPDIRECT3DINDEXBUFFER9 pIB;
hr = pMeshContainer->pOrigMesh->GetIndexBuffer(&pIB);
if (FAILED(hr))
goto e_Exit;
hr = pMeshContainer->pSkinInfo->GetMaxFaceInfluences(pIB, pMeshContainer->pOrigMesh->GetNumFaces(),
&NumMaxFaceInfl);
pIB->Release(); //?这里为什么要释放
if (FAILED(hr))
goto e_Exit;
// 12 entry palette guarantees that any triangle (4 independent influences per vertex of a tri)
// can be handled
//12个调色板保证所有三角形都被处理
NumMaxFaceInfl = min(NumMaxFaceInfl, 12);
if (m_d3dCaps.MaxVertexBlendMatrixIndex + 1 < NumMaxFaceInfl)
{
// HW does not support indexed vertex blending. Use SW instead
//如果硬件不支持顶点混和,就使用软件混和
pMeshContainer->NumPaletteEntries = min(256, pMeshContainer->pSkinInfo->GetNumBones());
pMeshContainer->UseSoftwareVP = true;
Flags |= D3DXMESH_SYSTEMMEM;
}
else
{
// using hardware - determine palette size from caps and number of bones
// If normals are present in the vertex data that needs to be blended for lighting, then
// the number of matrices is half the number specified by MaxVertexBlendMatrixIndex.
pMeshContainer->NumPaletteEntries = min( ( m_d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2,
pMeshContainer->pSkinInfo->GetNumBones() );
pMeshContainer->UseSoftwareVP = false;
Flags |= D3DXMESH_MANAGED;
}
hr = pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh
(
pMeshContainer->pOrigMesh,
Flags,
pMeshContainer->NumPaletteEntries,
pMeshContainer->pAdjacency,
NULL, NULL, NULL,
&pMeshContainer->NumInfl,
&pMeshContainer->NumAttributeGroups,
&pMeshContainer->pBoneCombinationBuf,
&pMeshContainer->MeshData.pMesh);
if (FAILED(hr))
goto e_Exit;
}
// if software skinning selected, use GenerateSkinnedMesh to create a mesh that can be used with UpdateSkinnedMesh
else if (m_SkinningMethod == SOFTWARE)
{
hr = pMeshContainer->pOrigMesh->CloneMeshFVF(D3DXMESH_MANAGED, pMeshContainer->pOrigMesh->GetFVF(),
m_pd3dDevice, &pMeshContainer->MeshData.pMesh);
if (FAILED(hr))
goto e_Exit;
hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(NULL, &pMeshContainer->NumAttributeGroups);
if (FAILED(hr))
goto e_Exit;
delete[] pMeshContainer->pAttributeTable;
pMeshContainer->pAttributeTable = new D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups];
if (pMeshContainer->pAttributeTable == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable, NULL);
if (FAILED(hr))
goto e_Exit;
// allocate a buffer for bone matrices, but only if another mesh has not allocated one of the same size or larger
if (m_NumBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones())
{
m_NumBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones();
// Allocate space for blend matrices
delete []m_pBoneMatrices;
m_pBoneMatrices = new D3DXMATRIXA16[m_NumBoneMatricesMax];
if (m_pBoneMatrices == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
}
}
else // invalid m_SkinningMethod value
{
// return failure due to invalid skinning method value
hr = E_INVALIDARG;
goto e_Exit;
}
e_Exit:
return hr;
}
//Summ:设置MeshContainer链表每个节点的矩阵指针
//Desc:设置每个MeshContainer节点的矩阵指针,每个MeshContainer都有相对应的若干个变换矩阵
// 这里每个Frame包含一个MeshContainer的链表,而影响这个MeshContainer的矩阵并非
// 一个,所以,尽管已经有了变换矩阵,但并非唯一影响这个MeshContainer的矩阵
//Para:
// pMeshContainerBase pMeshContainerBase链表的结构的首节点
HRESULT CSkinMesh::SetupBoneMatrixPointers(LPD3DXFRAME pFrame)
{
HRESULT hr;
if (pFrame->pMeshContainer != NULL)
{ //中序
hr = SetupBoneMatrixPointersOnMesh(pFrame->pMeshContainer);
if (FAILED(hr))
return hr;
}
if (pFrame->pFrameSibling != NULL)
{
hr = SetupBoneMatrixPointers(pFrame->pFrameSibling);
if (FAILED(hr))
return hr;
}
if (pFrame->pFrameFirstChild != NULL)
{
hr = SetupBoneMatrixPointers(pFrame->pFrameFirstChild);
if (FAILED(hr))
return hr;
}
return S_OK;
}
//Summ:设置MeshContainer每个节点的矩阵指针
//Desc:设置MeshContainer的矩阵指针,每个MeshContainer都有相对应的若干个变换矩阵
// 这里每个Frame包含一个MeshContainer的链表,而影响这个MeshContainer的矩阵并非
// 一个,所以,尽管已经有了变换矩阵,但并非唯一影响这个MeshContainer的矩阵
//Para:
// pMeshContainerBase pMeshContainerBase链表的结构的首节点
HRESULT CSkinMesh::SetupBoneMatrixPointersOnMesh(LPD3DXMESHCONTAINER pMeshContainerBase)
{
UINT iBone, cBones;
D3DXFRAME_DERIVED *pFrame;
D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
// if there is a skinmesh, then setup the bone matrices
//蒙皮动画,则设置骨骼的变换矩阵
if (pMeshContainer->pSkinInfo != NULL)
{
cBones = pMeshContainer->pSkinInfo->GetNumBones();
pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones]; //创建骨骼
if (pMeshContainer->ppBoneMatrixPtrs == NULL)
return E_OUTOFMEMORY;
for (iBone = 0; iBone < cBones; iBone++)
{
pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind(m_pFrameRoot,
pMeshContainer->pSkinInfo->GetBoneName(iBone));
if (pFrame == NULL)
return E_FAIL;
//初始化矩阵
pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix;
}
}
return S_OK;
}
//Summ:渲染
//Desc:渲染这个蒙皮动画
//Para:
// fElapsedAppTime:上一帧到当前帧的时间间隔,用于更新时间轴
// vPos: 蒙皮的位置,也就是根节点的位置
// angle: 角度
// scale: 比例
VOID CSkinMesh::Render(float fTimeFromLastFrame,D3DXVECTOR3 vPos,float angle,float scale)
{
if( 0.00f == fTimeFromLastFrame )
return;
m_fElapsedTime = fTimeFromLastFrame;
// Setup world matrix
D3DXMATRIXA16 matWorld,matWorld2;
D3DXMatrixRotationY(&matWorld2,angle);
D3DXMatrixScaling(&matWorld,scale,scale,scale);
D3DXMatrixMultiply(&matWorld,&matWorld,&matWorld2);
D3DXMatrixTranslation( &matWorld2, vPos.x, vPos.y,vPos.z );
D3DXMatrixMultiply(&matWorld,&matWorld,&matWorld2);
if(m_pAnimController)
{
#if ((D3D_SDK_VERSION & 0xFF) == 31)
if (m_bMoving)
m_pAnimController->SetTime(m_pAnimController->GetTime()+m_fElapsedTime );
else
m_pAnimController->SetTime(0);
#else
if (m_bMoving)
m_pAnimController->AdvanceTime(m_fElapsedTime,NULL);
else
m_pAnimController->ResetTime();
#endif
}
UpdateFrameMatrices(m_pFrameRoot, &matWorld);
//TODO:动态更新方盒,如果使用动态方盒,那么这里得到是方盒的世界坐标
// m_vMin=vPos;
// m_vMax=vPos;
// CalculateBondingBox(m_pFrameRoot,&m_vMin,&m_vMax);
DrawFrame(m_pFrameRoot);
}
VOID CSkinMesh::Render(float fTime, D3DXMATRIXA16 * matWorld )
{
m_fElapsedTime = fTime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -