📄 skinnedmesh.h
字号:
// Name: CAllocateHierarchy::DestroyMeshContainer()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
UINT iMaterial;
D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
SAFE_DELETE_ARRAY( pMeshContainer->Name );
SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );
SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );
SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );
// release all the allocated textures
if (pMeshContainer->ppTextures != NULL)
{
for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
{
SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] );
}
}
SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );
SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
SAFE_RELEASE( pMeshContainer->pSkinInfo );
SAFE_RELEASE( pMeshContainer->pOrigMesh );
SAFE_DELETE( pMeshContainer );
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 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;
/* If the device can only do 2 matrix blends, ConvertToBlendedMesh cannot approximate all meshes to it
Thus we split the mesh in two parts: The part that uses at most 2 matrices and the rest. The first is
drawn using the device's HW vertex processing and the rest is drawn using SW vertex processing. */
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(),
Device, &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
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 vertex shader indexed skinning mode selected, use ConvertToIndexedsBlendedMesh to generate drawable mesh
else if ((m_SkinningMethod == D3DINDEXEDVS) || (m_SkinningMethod == D3DINDEXEDHLSLVS))
{
// Get palette size
// First 9 constants are used for other data. Each 4x3 matrix takes up 3 constants.
// (96 - 9) /3 i.e. Maximum constant count - used constants
UINT MaxMatrices = 26;
pMeshContainer->NumPaletteEntries = min(MaxMatrices, pMeshContainer->pSkinInfo->GetNumBones());
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
if (m_d3dCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1))
{
pMeshContainer->UseSoftwareVP = false;
Flags |= D3DXMESH_MANAGED;
}
else
{
pMeshContainer->UseSoftwareVP = true;
Flags |= D3DXMESH_SYSTEMMEM;
}
SAFE_RELEASE(pMeshContainer->MeshData.pMesh);
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;
// FVF has to match our declarator. Vertex shaders are not as forgiving as FF pipeline
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, Device, &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;
// the vertex shader is expecting to interpret the UBYTE4 as a D3DCOLOR, so update the type
// NOTE: this cannot be done with CloneMesh, that would convert the UBYTE4 data to float and then to D3DCOLOR
// this is more of a "cast" operation
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;
// 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;
}
}
}
// 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(),
Device, &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;
}
//-----------------------------------------------------------------------------
// Name: FrameMove()
// Desc: Called once per frame, the call is the entry point for animating
// the scene.
//-----------------------------------------------------------------------------
HRESULT FrameMove()
{
// Setup world matrix
D3DXMATRIXA16 matWorld;
D3DXMatrixTranslation( &matWorld, -m_vObjectCenter.x,
-m_vObjectCenter.y,
-m_vObjectCenter.z );
D3DXMatrixMultiply( &matWorld, &matWorld, m_ArcBall->GetRotationMatrix() );
D3DXMatrixMultiply( &matWorld, &matWorld, m_ArcBall->GetTranslationMatrix() );
Device->SetTransform( D3DTS_WORLD, &matWorld );
D3DXVECTOR3 vEye( 0, 0, -2*m_fObjectRadius);
D3DXVECTOR3 vAt( 0, 0, 0 );
D3DXVECTOR3 vUp( 0, 1, 0 );
D3DXMatrixLookAtLH( &m_matView, &vEye, &vAt, &vUp);
Device->SetTransform( D3DTS_VIEW, &m_matView );
if (m_pAnimController != NULL)
m_pAnimController->SetTime(m_pAnimController->GetTime() + m_fElapsedTime);
UpdateFrameMatrices(m_pFrameRoot, &matWorld);
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -