原文出處:http://blog.csdn.net/cywater2000/archive/2006/01/05/571299.aspx
一.公式:
FinalPos = MeshPos + ∑( Difference_i * Weight_i)
= MeshPos + ∑( (NewMeshPos_i - MeshPos) * Weight_i )
= MeshPos + ∑( (MeshPos × OffsetMatix_i × CombinedMatrix_i - MeshPos) * Weight_i ) [1]
其中:
MeshPos: 某頂點在mesh中的原始位置
NewMeshPos_i: 此頂點受某骨骼i影響后變換到的新位置
Difference_i: 兩者之間的位移差值
Weight_i:: 此頂點受某骨骼i的影響權(quán)重
OffsetMatix_i: 骨骼i的偏移矩陣
CombinedMatrix_i: 骨骼i經(jīng)過層次更新后的混合矩陣
∑: 求和(對所有影響該頂點的骨骼)
FinalPos: 此頂點的最終位置
法線計算同理。
二.模擬代碼(沒有優(yōu)化):
HRESULT UpdateSkinnedMesh(ID3DXSkinInfo *pSkinInfo,
const D3DXMATRIX *pBoneTransforms,
const D3DXMATRIX *pBoneInvTransposeTransforms, //not use(原函數(shù)也沒用)
LPCVOID pVerticesSrc,
PVOID pVerticesDst,
//注意下面增加的兩個變量是原函數(shù)在調(diào)用時沒有的,因為ID3DXSkinInfo的內(nèi)部機制可以獲得
DWORD numTotalVerts, // 指mesh的頂點個數(shù)
DWORD dwStride // 指mesh每個頂點的間距,即每個頂點結(jié)構(gòu)的大小
)
{
DWORD *pVertsIndic = NULL;
float *pVertsWeigh = NULL;
DWORD dwNumVerts;
DWORD offsetByte;
BYTE *pDest = (BYTE*)pVerticesDst; //目標(biāo)頂點緩沖
const BYTE *pSrc = (BYTE*)pVerticesSrc; //源頂點緩沖
memcpy(pDest, pSrc, numTotalVerts * dwStride);
for(DWORD i = 0; i < pSkinInfo->GetNumBones(); i++)
{
dwNumVerts = pSkinInfo->GetNumBoneInfluences(i); //得到受影響的頂點個數(shù)
if(dwNumVerts <= 0)
continue;
pVertsIndic = new DWORD[dwNumVerts];
pVertsWeigh = new float[dwNumVerts];
pSkinInfo->GetBoneInfluence(i, pVertsIndic, pVertsWeigh);
while(dwNumVerts--)
{
DWORD index = pVertsIndic[dwNumVerts]; //當(dāng)前受影響的頂點索引
float weight = pVertsWeigh[dwNumVerts]; //當(dāng)前受影響頂點的權(quán)重
offsetByte = index * dwStride;
D3DXVECTOR3 vecPos = *(D3DXVECTOR3 *)(pSrc + offsetByte); //位置
D3DXVECTOR3 vecNor = *(D3DXVECTOR3 *)(pSrc + offsetByte + sizeof(D3DXVECTOR3)); //法線
D3DXVECTOR3 vecPos2, vecNor2;
D3DXVec3TransformCoord(&vecPos2, &vecPos, &pBoneTransforms[i]);
D3DXVec3TransformNormal(&vecNor2, &vecNor, &pBoneTransforms[i]);
D3DXVECTOR3 *pV = (D3DXVECTOR3 *)(pDest + offsetByte);
D3DXVECTOR3 *pN = (D3DXVECTOR3 *)(pDest + offsetByte + sizeof(D3DXVECTOR3));
D3DXVECTOR3 diff = (vecPos2 - vecPos) * weight;
*pV += diff;
diff = (vecNor2 - vecNor) * weight;
*pN += diff;
}
delete[] pVertsIndic;
delete[] pVertsWeigh;
}
return S_OK;
}
注意在調(diào)用UpdateSkinnedMesh前,pBoneTransforms已經(jīng)是OffsetMatix與CombinedMatrix的連接矩陣了(ID3DXSkinInfo::UpdateSkinnedMesh也是這么要求的)。
重要更新:
骨骼動畫屬于Geometry Blending,因此標(biāo)準(zhǔn)做法應(yīng)該是:

[2]
即FinalPos =∑(NewMeshPos_i * Weight_i) + NewMeshPos_n * (1 - ∑Weight_i ) , i=0,1..n-1
=∑(MeshPos
× OffsetMatix_i × CombinedMatrix_i * Weight_i) + (MeshPos ×
OffsetMatix_n × CombinedMatrix_n) * (1 - ∑Weight_i ) , i=0,1..n-1 [3]
(顯然只有當(dāng)影響頂點的所有權(quán)重之和等于1時,公式[1]與[3]才等價)