一.公式:
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的影响权重
OffsetMatix_i: 骨骼i的偏移矩阵
CombinedMatrix_i: 骨骼i经过层次更新后的混合矩阵
∑: 求和(对所有影响该顶点的骨骼)
FinalPos: 此顶点的最终位置
法线计算同理。
二.模拟代码(没有优化):
const D3DXMATRIX * pBoneTransforms,
const D3DXMATRIX * pBoneInvTransposeTransforms, // not use(原函数也没用)
LPCVOID pVerticesSrc,
PVOID pVerticesDst,
// 注意下面增加的两个变量是原函数在调用时没有的,因为ID3DXSkinInfo的内部机制可以获得
DWORD numTotalVerts, // 指mesh的顶点个数
DWORD dwStride // 指mesh每个顶点的间距,即每个顶点结构的大小
)
{
DWORD * pVertsIndic = NULL;
float * pVertsWeigh = NULL;
DWORD dwNumVerts;
DWORD offsetByte;
BYTE * pDest = (BYTE * )pVerticesDst; // 目标顶点缓冲
const BYTE * pSrc = (BYTE * )pVerticesSrc; // 源顶点缓冲
memcpy(pDest, pSrc, numTotalVerts * dwStride);
for (DWORD i = 0 ; i < pSkinInfo -> GetNumBones(); i ++ )
{
dwNumVerts = pSkinInfo -> GetNumBoneInfluences(i); // 得到受影响的顶点个数
if (dwNumVerts <= 0 )
continue ;
pVertsIndic = new DWORD[dwNumVerts];
pVertsWeigh = new float [dwNumVerts];
pSkinInfo -> GetBoneInfluence(i, pVertsIndic, pVertsWeigh);
while (dwNumVerts -- )
{
DWORD index = pVertsIndic[dwNumVerts]; // 当前受影响的顶点索引
float weight = pVertsWeigh[dwNumVerts]; // 当前受影响顶点的权重
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;
}
注意在调用UpdateSkinnedMesh前,pBoneTransforms已经是OffsetMatix与CombinedMatrix的连接矩阵了(ID3DXSkinInfo::UpdateSkinnedMesh也是这么要求的)。
重要更新: