zfxSkinMesh.cpp
上传用户:junlon
上传日期:2022-01-05
资源大小:39075k
文件大小:10k
源码类别:

DirextX编程

开发平台:

Visual C++

  1. //=============================================================================
  2. // zfxSkinMesh.cpp: 蒙皮骨骼动画模型类的实现
  3. //=============================================================================
  4. #include "zfxSkinMesh.h"
  5. //--------------------------------------------------------------------
  6. // 构造函数和析构函数  Construction/Destruction
  7. //--------------------------------------------------------------------
  8. CZFXSkinMesh::CZFXSkinMesh()
  9. {
  10. m_bPlayAnim          = true;
  11. m_pd3dDevice         = NULL;
  12.     m_pAnimController    = NULL;
  13.     m_pFrameRoot         = NULL;
  14. m_pAlloc = new CAllocateHierarchy();
  15. }
  16. //-----------------------------------------------------------------------------
  17. // 构造函数和析构函数 
  18. //-----------------------------------------------------------------------------
  19. CZFXSkinMesh::~CZFXSkinMesh()
  20. {
  21. }
  22. //-----------------------------------------------------------------------------
  23. // 创建并加载蒙皮网格模型
  24. //-----------------------------------------------------------------------------
  25. HRESULT CZFXSkinMesh::OnCreate(LPDIRECT3DDEVICE9 pD3DDevice, WCHAR *strFileName)
  26. {
  27. HRESULT hr;
  28. m_pd3dDevice = pD3DDevice;
  29. hr = LoadFromXFile(strFileName);
  30. if(FAILED(hr))
  31. return hr;
  32. return S_OK;
  33. }
  34. //-----------------------------------------------------------------------------
  35. // 从文件加载蒙皮网格模型
  36. //-----------------------------------------------------------------------------
  37. HRESULT CZFXSkinMesh::LoadFromXFile(WCHAR *strFileName)
  38. {
  39.     HRESULT hr;
  40. //从.X文件加载层次框架和动画数据
  41.     hr = D3DXLoadMeshHierarchyFromX(strFileName, D3DXMESH_MANAGED, m_pd3dDevice, 
  42.                             m_pAlloc, NULL, &m_pFrameRoot, &m_pAnimController);
  43. if(FAILED(hr))
  44.         return hr;
  45. //建立各级框架的组合变换矩阵
  46.     hr = SetupBoneMatrixPointers(m_pFrameRoot);  
  47. if(FAILED(hr))
  48.         return hr;
  49. //计算框架对象的边界球
  50.     hr = D3DXFrameCalculateBoundingSphere(m_pFrameRoot, &m_vObjectCenter, &m_fObjectRadius);
  51. if(FAILED(hr))
  52.         return hr;
  53. return S_OK;
  54. }
  55. //--------------------------------------------------------------------------
  56. // 仅在LoadFromXFile中调用。调用子函数SetupBoneMatrixPointersOnMesh()
  57. // 安置好各级框架(实际上是各个骨骼)的组合变换矩阵。
  58. // 注意: 在这里其实并没有计算出各个骨骼的组合变换矩阵,只是为每个矩阵开辟了相应
  59. // 的存储空间,真正的计算是在函数CSkinMesh::UpdateFrameMatrices()中完成的。
  60. //---------------------------------------------------------------------------
  61. HRESULT CZFXSkinMesh::SetupBoneMatrixPointers(LPD3DXFRAME pFrame)
  62. {
  63.     HRESULT hr;
  64.     if (pFrame->pMeshContainer != NULL)
  65.     {
  66.         hr = SetupBoneMatrixPointersOnMesh(pFrame->pMeshContainer);  //调用子函数
  67.         if (FAILED(hr))
  68.             return hr;
  69.     }
  70.     if (pFrame->pFrameSibling != NULL)
  71.     {
  72.         hr = SetupBoneMatrixPointers(pFrame->pFrameSibling);   //递归
  73.         if (FAILED(hr))
  74.             return hr;
  75.     }
  76.     if (pFrame->pFrameFirstChild != NULL)
  77.     {
  78.         hr = SetupBoneMatrixPointers(pFrame->pFrameFirstChild);  //递归
  79.         if (FAILED(hr))
  80.             return hr;
  81.     }
  82.     return S_OK;
  83. }
  84. //-----------------------------------------------------------------------------
  85. // 仅在SetupBoneMatrixPointers()中被调用,设置每个骨骼的组合变换矩阵
  86. //-----------------------------------------------------------------------------
  87. HRESULT CZFXSkinMesh::SetupBoneMatrixPointersOnMesh(LPD3DXMESHCONTAINER pMeshContainerBase)
  88. {
  89.     UINT iBone, cBones;  // cBones表示骨骼数量,iBone表示循环变量
  90.     D3DXFRAME_DERIVED *pFrame;
  91. //先强制转为扩展型
  92.     D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
  93.     // 只有蒙皮网格模型才有骨骼矩阵
  94.     if (pMeshContainer->pSkinInfo != NULL)
  95.     {
  96. //得到骨骼数量
  97.         cBones = pMeshContainer->pSkinInfo->GetNumBones();
  98. //申请存储骨骼矩阵的空间
  99.         pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones];     
  100. if (pMeshContainer->ppBoneMatrixPtrs == NULL)
  101.             return E_OUTOFMEMORY;
  102.         for (iBone = 0; iBone < cBones; iBone++)
  103.         {
  104. //找到框架
  105.             pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind(m_pFrameRoot, pMeshContainer->pSkinInfo->GetBoneName(iBone));
  106.             if (pFrame == NULL)
  107.                 return E_FAIL;
  108. //将框架的组合变换矩阵赋值给对应的骨骼的复合变换矩阵
  109.             pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix;
  110. }
  111.     }
  112.     return S_OK;
  113. }
  114. //-----------------------------------------------------------------------------
  115. // 更新框架并绘制框架
  116. // (1)用m_pAnimController->AdvanceTime()设置时间,m_pAnimController是
  117. //    类LPD3DXANIMATIONCONTROLLER的一个对象
  118. // (2)用函数CSkinMesh::UpdateFrameMatrices()更新框架
  119. // (3)用函数CSkinMesh::DrawFrame()绘制框架
  120. //-----------------------------------------------------------------------------
  121. HRESULT CZFXSkinMesh::Render(D3DXMATRIX* matWorld, float fElapsedAppTime)
  122. {
  123.     if( 0.0f == fElapsedAppTime ) 
  124.         return S_OK;
  125. if (m_bPlayAnim && m_pAnimController != NULL)
  126. m_pAnimController->AdvanceTime( fElapsedAppTime, NULL );
  127. UpdateFrameMatrices(m_pFrameRoot, matWorld);  //调用子函数
  128. DrawFrame(m_pFrameRoot);  //调用子函数
  129. return S_OK;
  130. }
  131. //-----------------------------------------------------------------------------
  132. // 计算各个骨骼的组合变换矩阵
  133. //-----------------------------------------------------------------------------
  134. void CZFXSkinMesh::UpdateFrameMatrices(LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix)
  135. {
  136.     D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
  137.     if (pParentMatrix != NULL)
  138.         D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &pFrame->TransformationMatrix, pParentMatrix);
  139.     else
  140.         pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;
  141.     if (pFrame->pFrameSibling != NULL)
  142.     {
  143.         UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);
  144.     }
  145.     if (pFrame->pFrameFirstChild != NULL)
  146.     {
  147.         UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix);
  148.     }
  149. }
  150. //-----------------------------------------------------------------------------
  151. // 绘制框架.
  152. // 先用CSkinMesh::DrawMeshContainer()绘制一个LPD3DXMESHCONTAINER类型
  153. // 的变量pMeshContainer.然后递归绘制同一级框架和子一级框架。
  154. //-----------------------------------------------------------------------------
  155. void CZFXSkinMesh::DrawFrame(LPD3DXFRAME pFrame)
  156. {
  157.     LPD3DXMESHCONTAINER pMeshContainer;
  158.     pMeshContainer = pFrame->pMeshContainer;
  159.     while (pMeshContainer != NULL)
  160.     {
  161.         DrawMeshContainer(pMeshContainer, pFrame); //调用子函数
  162.         pMeshContainer = pMeshContainer->pNextMeshContainer;
  163.     }
  164.     if (pFrame->pFrameSibling != NULL)
  165.     {
  166.         DrawFrame(pFrame->pFrameSibling);
  167.     }
  168.     if (pFrame->pFrameFirstChild != NULL)
  169.     {
  170.         DrawFrame(pFrame->pFrameFirstChild);
  171.     }
  172. }
  173. //-----------------------------------------------------------------------------
  174. // DrawMeshContainer()
  175. // Called to render a mesh in the hierarchy
  176. //-----------------------------------------------------------------------------
  177. void CZFXSkinMesh::DrawMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase)
  178. {
  179. D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
  180. D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
  181. UINT iMaterial;
  182. UINT iAttrib;
  183. LPD3DXBONECOMBINATION pBoneComb;
  184. UINT iMatrixIndex;
  185. UINT iPaletteEntry;
  186. D3DXMATRIXA16 matTemp;
  187. if (pMeshContainer->pSkinInfo != NULL) //如果是蒙皮网格
  188. {
  189. //检查是否使用软件顶点混合
  190. //如果当前硬件不支持, 则使用软件顶点处理
  191. if (pMeshContainer->UseSoftwareVP)
  192. m_pd3dDevice->SetSoftwareVertexProcessing(true);
  193. //启用索引顶点混合
  194. if (pMeshContainer->NumInfl)
  195. m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, true);
  196. //根据影响当前网格模型顶点的骨骼数量, 设置需要使用的混合矩阵索引数量
  197. if (pMeshContainer->NumInfl == 1)
  198. m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS);
  199. else if(pMeshContainer->NumInfl == 2)
  200. m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS);
  201. else if(pMeshContainer->NumInfl == 3)
  202. m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_2WEIGHTS);
  203. else
  204. m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS);
  205. //逐个子网格渲染进行渲染
  206. pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
  207. for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
  208. {
  209. //设置混合矩阵
  210. for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries; ++iPaletteEntry)
  211. {
  212. iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry];
  213. if (iMatrixIndex != UINT_MAX)
  214. {
  215. D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], 
  216.                  pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
  217. m_pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( iPaletteEntry ), &matTemp );
  218. }
  219. }
  220. //设置材质和纹理
  221. m_pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );
  222. m_pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );
  223. //渲染子网格模型
  224. pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib );
  225. }
  226. //恢复顶点混合状态
  227. m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
  228. m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
  229. //恢复顶点处理模式
  230. if (pMeshContainer->UseSoftwareVP)
  231. m_pd3dDevice->SetSoftwareVertexProcessing(false);
  232. else  // 如果只是普通网格,在添加材质后就绘制它。
  233. {
  234. m_pd3dDevice->SetTransform(D3DTS_WORLD, &pFrame->CombinedTransformationMatrix);
  235. for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
  236. {
  237. m_pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D );
  238. m_pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] );
  239. pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial);
  240. }
  241. }
  242. }
  243. //-----------------------------------------------------------------------------
  244. // 释放蒙皮网格模型
  245. //-----------------------------------------------------------------------------
  246. HRESULT CZFXSkinMesh::OnDestory()
  247. {
  248. D3DXFrameDestroy(m_pFrameRoot, m_pAlloc);
  249.     SAFE_RELEASE(m_pAnimController);
  250. delete m_pAlloc;
  251. return S_OK;
  252. }