skeletal:骨骼动画(Skeletal Animation)(四)



我们目标是根据骨骼动画来更新模型看看手上材料 1)骨骼动画数据节中我们已经读出了AnimationSet、Animation和AnimationKey这些动画数据我们现在要做就是把它们应用到骨骼上面去AnimationSet只是标明了我们要播放动画名称关键处理在Animation和AnimationKey上面Animation包含了所对应骨骼名称下属AnimationKey包含了坐标变换类型以及对应时间戳我们也把AnimationKey看做个关键帧下面要做就是根据当前时间判断动画落在哪两个关键帧中间例如key1和key2然后求出插值系数scaler,

scaler = (当前时间-key1.时间)/(key2.时间-key1.时间)

求出插值系数后骨骼当前位置就可以用下面思路方法求出注意各种key类型求插值思路方法不样,

switch( Key类型 )
{
旋转:

...

// 4元数插值
D3DXQUATERNION RotationQuaternion;
D3DXQuaternionSlerp(
&RotationQuaternion,
&pAnimationKey->pQuaternionKeys[Key1].value,
&pAnimationKey->pQuaternionKeys[Key2].value,
Scaler);

// 应用旋转矩阵
D3DXMATRIX RotationMatrix;
D3DXMatrixRotationQuaternion( &RotationMatrix, &RotationQuaternion );
pAnimation->pBone->TransformationMatrix *= RotationMatrix;

;

平移和缩放:

...

// 矢量插值
D3DXVECTOR3 InterpolatedVector =
pAnimationKey->pVectorKeys[Key1].value + Scaler *
( pAnimationKey->pVectorKeys[Key2].value - pAnimationKey->pVectorKeys[Key1].value );

( pAnimationKey->Type XAnimationKey::KeyType::Scaling )
{
// 应用缩放矩阵
D3DXMATRIX ScalingMatrix;
D3DXMatrixScaling(
&ScalingMatrix, InterpolatedVector.x, InterpolatedVector.y, InterpolatedVector.z );

pAnimation->pBone->TransformationMatrix *= ScalingMatrix;
}

{
// 应用平移矩阵
D3DXMATRIX TranslationMatrix;
D3DXMatrixTranslation(
&TranslationMatrix, InterpolatedVector.x, InterpolatedVector.y, InterpolatedVector.z );
pAnimation->pBone->TransformationMatrix *= TranslationMatrix;
}

;

坐标变换矩阵:

...

// 矩阵插值
D3DXMATRIX TransformMatrix =
pAnimationKey->pMatrixKeys[Key1].value + Scaler *
( pAnimationKey->pMatrixKeys[Key2].value - pAnimationKey->pMatrixKeys[Key1].value );

// 应用坐标变换矩阵
pAnimation->pBone->TransformationMatrix *= TransformMatrix;

;
} // switch

这样我们就把根据当前时间计算出来插值坐标变换矩阵应用到骨骼上了

2)骨骼数据在从文件中读出来时候我们已经利用pFrameSibling和pFrameFirstChild两个字段构造了个层次结构注意骨骼中TransformationMatrix包含是当前骨骼相对于父骨骼坐标变换应用到mesh上时候我们需要相对于根骨骼坐标变换因此我们要做下处理简单个递归

//-----------------------------------------------------------------------------
// 名称: UpdateHierarchy
// 描述: 计算本节点及所有兄弟、子节点相对于根节点偏移矩阵
//-----------------------------------------------------------------------------
void UpdateHierarchy( D3DXMATRIX *matTrans = NULL )
{
D3DXMATRIX matIdentity;

// 根节点偏移矩阵为单位矩阵
( NULL matTrans )
{
D3DXMatrixIdentity( &matIdentity );
matTrans = &matIdentity;
}

// 计算偏移矩阵
matCombined = TransformationMatrix * ( *matTrans );

// 更新兄弟节点
( pFrameSibling )
( ( D3DXFRAME_EX* )pFrameSibling )->UpdateHierarchy( matTrans );

// 更新子节点
( pFrameFirstChild )
( ( D3DXFRAME_EX* )pFrameFirstChild )->UpdateHierarchy( &matCombined );
}

通过在根骨骼上我们就可以在自定义matCombined字段中得到各个骨骼相对于根骨骼坐标变换矩阵.

3)mesh数据mesh数据相对简单ID3DXMesh和ID3DXSkinInfo接口为我们了做大部分工作不过天底下没有免费午餐为了让它们运转起来我们还是要做些额外努力在步骤1里面我们已经通过插值得到了骨骼当前坐标变换矩阵不过这个坐标变换是相对于模型本地坐标为了应用到mesh上我们需要将坐标对齐到mesh中心,

// 首先bone转换到以mesh中心为坐标原点坐标系然后再应用frame坐标变换矩阵
for( DWORD i=0; i<m_pRootMeshContainer->pSkinInfo->GetNumBones; i )
{
m_pRootMeshContainer->pBoneMatrices[i] =
*( m_pRootMeshContainer->pSkinInfo->GetBoneOffMatrix( i ) );

( m_pRootMeshContainer->ppFrameMatrices[i] )
m_pRootMeshContainer->pBoneMatrices[i] *= *m_pRootMeshContainer->ppFrameMatrices[i];
}

这样所有数据都准备好了用ID3DXSkinInfo思路方法来更新骨骼关联每个顶点坐标(每个顶点根据关联所有骨骼坐标变换矩阵乘以对应权重再相加来得到最终应用到顶点上坐标变换矩阵)

m_pRootMeshContainer->pSkinInfo->UpdateSkinnedMesh(
m_pRootMeshContainer->pBoneMatrices, NULL, pSrcVertex, pDestVertex );

到此切准备都结束了! 绘制Mesh动作和平常设置材质和纹理然后DrawSubSet思路方法这个想来对大家是没有什么难度事情如何样是不是想从头再看遍回味下呢? 呵呵

(附件里面是测试工程编译环境为VS.NET2003, DXSDK(October 2004)大家有什么不明白或者我哪里说错欢迎给我写信或者留言)





Tags:  theanimation animation skeletalhound skeletal

延伸阅读

最新评论

发表评论