📄 skinmesh.cpp
字号:
}
VOID CSkinMesh::DrawFrame( LPD3DXFRAME pFrame )
{
LPD3DXMESHCONTAINER pMeshContainer;
pMeshContainer = pFrame->pMeshContainer;
while(pMeshContainer != NULL)
{
DrawMeshContainer( pMeshContainer, pFrame ); // 绘制框架
pMeshContainer = pMeshContainer->pNextMeshContainer;
}
if (pFrame->pFrameSibling != NULL)
{
DrawFrame(pFrame->pFrameSibling);
}
if (pFrame->pFrameFirstChild != NULL)
{
DrawFrame(pFrame->pFrameFirstChild);
}
}
//-----------------------------------------------------------------------------
// Name: DrawMeshContainer()
// Desc: 渲染层次中的网格模型
//-----------------------------------------------------------------------------
VOID CSkinMesh::DrawMeshContainer( LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase )
{
D3DXMESHCONTAINER_EX *pMeshContainer = (D3DXMESHCONTAINER_EX*)pMeshContainerBase;
D3DXFRAME_EX *pFrame = (D3DXFRAME_EX*)pFrameBase;
UINT iMaterial;
UINT NumBlend;
UINT iAttrib;
DWORD AttribIdPrev;
LPD3DXBONECOMBINATION pBoneComb;
UINT iMatrixIndex;
UINT iPaletteEntry;
D3DXMATRIXA16 matTemp;
// first check for skinning
if (pMeshContainer->pSkinInfo != NULL)
{
if (m_SkinningMethod == D3DNONINDEXED)
{
AttribIdPrev = UNUSED32;
pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
// Draw using default vtx processing of the device (typically HW)
for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
{
NumBlend = 0;
for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
{
if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)
{
NumBlend = i;
}
}
if (m_d3dCaps.MaxVertexBlendMatrices >= NumBlend + 1)
{
// first calculate the world matrices for the current set of blend weights and get the accurate count of the number of blends
for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
{
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
m_pID3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp );
}
}
m_pID3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend);
// lookup the material used for this subset of faces
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32))
{
m_pID3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );
m_pID3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );
AttribIdPrev = pBoneComb[iAttrib].AttribId;
}
// draw the subset now that the correct material and matrices are loaded
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib);
}
}
// If necessary, draw parts that HW could not handle using SW
if (pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups)
{
AttribIdPrev = UNUSED32;
m_pID3dDevice->SetSoftwareVertexProcessing(TRUE);
for (iAttrib = pMeshContainer->iAttributeSW; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
{
NumBlend = 0;
for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
{
if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)
{
NumBlend = i;
}
}
if (m_d3dCaps.MaxVertexBlendMatrices < NumBlend + 1)
{
// first calculate the world matrices for the current set of blend weights and get the accurate count of the number of blends
for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
{
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
m_pID3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp );
}
}
m_pID3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend);
// lookup the material used for this subset of faces
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32))
{
m_pID3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );
m_pID3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );
AttribIdPrev = pBoneComb[iAttrib].AttribId;
}
// draw the subset now that the correct material and matrices are loaded
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib);
}
}
m_pID3dDevice->SetSoftwareVertexProcessing(FALSE);
}
m_pID3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0);
}
else if (m_SkinningMethod == D3DINDEXED)
{
// if hw doesn't support indexed vertex processing, switch to software vertex processing
if (pMeshContainer->UseSoftwareVP)
{
m_pID3dDevice->SetSoftwareVertexProcessing(TRUE);
}
// set the number of vertex blend indices to be blended
if (pMeshContainer->NumInfl == 1)
m_pID3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS);
else
m_pID3dDevice->SetRenderState(D3DRS_VERTEXBLEND, pMeshContainer->NumInfl - 1);
if (pMeshContainer->NumInfl)
m_pID3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);
// for each attribute group in the mesh, calculate the set of matrices in the palette and then draw the mesh subset
pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
{
// first calculate all the world matrices
for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries;
++iPaletteEntry)
{
iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry];
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
m_pID3dDevice->SetTransform( D3DTS_WORLDMATRIX( iPaletteEntry ), &matTemp );
}
}
// setup the material of the mesh subset - REMEMBER to use the original pre-skinning attribute id to get the correct material id
m_pID3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );
m_pID3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );
// finally draw the subset with the current world matrix palette and material state
pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib );
}
// reset blending state
m_pID3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
m_pID3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0);
// remember to reset back to hw vertex processing if software was required
if (pMeshContainer->UseSoftwareVP)
{
m_pID3dDevice->SetSoftwareVertexProcessing(FALSE);
}
}
else if (m_SkinningMethod == SOFTWARE)
{
D3DXMATRIX Identity;
DWORD cBones = pMeshContainer->pSkinInfo->GetNumBones();
DWORD iBone;
PBYTE pbVerticesSrc;
PBYTE pbVerticesDest;
// set up bone transforms
for (iBone = 0; iBone < cBones; ++iBone)
{
D3DXMatrixMultiply
(
&m_pBoneMatrices[iBone], // output
&pMeshContainer->pBoneOffsetMatrices[iBone],
pMeshContainer->ppBoneMatrixPtrs[iBone]
);
}
// set world transform
D3DXMatrixIdentity(&Identity);
m_pID3dDevice->SetTransform(D3DTS_WORLD, &Identity);
pMeshContainer->pOrigMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbVerticesSrc);
pMeshContainer->MeshData.pMesh->LockVertexBuffer(0, (LPVOID*)&pbVerticesDest);
// generate skinned mesh
pMeshContainer->pSkinInfo->UpdateSkinnedMesh(m_pBoneMatrices, NULL, pbVerticesSrc, pbVerticesDest);
pMeshContainer->pOrigMesh->UnlockVertexBuffer();
pMeshContainer->MeshData.pMesh->UnlockVertexBuffer();
for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
{
m_pID3dDevice->SetMaterial(&(pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D));
m_pID3dDevice->SetTexture(0, pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId]);
pMeshContainer->MeshData.pMesh->DrawSubset(pMeshContainer->pAttributeTable[iAttrib].AttribId);
}
}
else // bug out as unsupported mode
{
return;
}
}
else // standard mesh, just draw it after setting material properties
{
m_pID3dDevice->SetTransform(D3DTS_WORLD, &pFrame->CombinedTransformationMatrix);
for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
{
m_pID3dDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D );
m_pID3dDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] );
pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial);
}
}
}
VOID CSkinMesh::UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix )
{
D3DXFRAME_EX *pFrame = (D3DXFRAME_EX*)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 );
}
}
VOID CSkinMesh::SetAnim(BOOL bAnim)
{
m_bMoving=bAnim;
if(!m_bMoving && m_pIAnimController)
{
#if ((D3D_SDK_VERSION&0xFF)== 31)
m_pIAnimController->SetTime(0);
#else
m_pIAnimController->ResetTime();
#endif
}
}
BOOL CSkinMesh::SetAnimationName( char *strAnimName )
{
if(!m_bMoving || !m_pIAnimController )
return FALSE;
DWORD nAnimSet;
char strTempName[256];
nAnimSet = m_pIAnimController->GetNumAnimationSets();
LPD3DXANIMATIONSET pAnimSet;
for(DWORD i=0;i<nAnimSet;i++)
{
m_pIAnimController->GetAnimationSet( i, &pAnimSet );
strcpy_s( strTempName, _tcslen(pAnimSet->GetName())+1, pAnimSet->GetName() );
if(strcmp(strAnimName,strTempName)==0)
{
m_pIAnimController->SetTrackAnimationSet( 0, pAnimSet );
return TRUE;
}
}
SAFE_RELEASE( pAnimSet );
return FALSE;
};
//-----------------------------------------
//Name:Intersect
//Desc:使用索引和顶点缓冲区,求Mesh和射线交点
//2006/6/27 JohnsonFeng
//Use: IntersectIndexBuffer
//-----------------------------------------
BOOL CSkinMesh::InterSect( D3DVECTOR *pRayOrig,
D3DVECTOR *pRayDir,D3DVECTOR* pVRet)
{
return S_OK;
}
HRESULT CSkinMesh::CalculateBondingBox( LPD3DXFRAME pFrameParent, D3DXVECTOR3 *pVmin, D3DXVECTOR3 *pVmax ) // 计算模型的包围盒,通过参数返回包围盒数据
{
static LPVOID pV;
static LPD3DXMESH pMesh;
static LPD3DXMATRIX pMat;
static D3DXVECTOR3 vMin,vMax;
static D3DXVECTOR3 vTransFormed;
if( pFrameParent->pMeshContainer )
{
pMesh = pFrameParent->pMeshContainer->MeshData.pMesh;
pMat = &( ((D3DXFRAME_EX*)pFrameParent)->CombinedTransformationMatrix );
pMesh->LockVertexBuffer( 0,&pV ); // 锁定顶点缓冲区
D3DXComputeBoundingBox( (LPD3DXVECTOR3)pV, pMesh->GetNumVertices(), pMesh->GetNumBytesPerVertex(), &vMin, &vMax ); // 创建包围盒
vTransFormed.x = pMat->_11*vMin.x + pMat->_21*vMin.y + pMat->_31*vMin.z + pMat->_41;
vTransFormed.y = pMat->_12*vMin.x + pMat->_22*vMin.y + pMat->_32*vMin.z + pMat->_42;
vTransFormed.z = pMat->_13*vMin.x + pMat->_23*vMin.y + pMat->_33*vMin.z + pMat->_43;
if(vTransFormed.x<pVmin->x) pVmin->x = vTransFormed.x;
if(vTransFormed.y<pVmin->y) pVmin->y = vTransFormed.y;
if(vTransFormed.z<pVmin->z) pVmin->z = vTransFormed.z;
vTransFormed.x=pMat->_11*vMax.x+pMat->_21*vMax.y+pMat->_31*vMax.z+pMat->_41;
vTransFormed.y=pMat->_12*vMax.x+pMat->_22*vMax.y+pMat->_32*vMax.z+pMat->_42;
vTransFormed.z=pMat->_13*vMax.x+pMat->_23*vMax.y+pMat->_33*vMax.z+pMat->_43;
if(vTransFormed.x>pVmax->x) pVmax->x = vTransFormed.x;
if(vTransFormed.y>pVmax->y) pVmax->y = vTransFormed.y;
if(vTransFormed.z>pVmax->z) pVmax->z = vTransFormed.z;
pMesh->UnlockVertexBuffer();
}
//else return S_OK;
if( pFrameParent->pFrameSibling )
CalculateBondingBox(pFrameParent->pFrameSibling,pVmin,pVmax);
if( pFrameParent->pFrameFirstChild )
CalculateBondingBox( pFrameParent->pFrameFirstChild, pVmin, pVmax );
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -