X文件里的动画不是skin mesh仅有的;它们对X文件里的任何的帧都是适用的.X文件存储了关键帧而程序则应用线性插值的方法产生中间帧.有4种动画关键帧:转动,缩放,位置,矩阵.转动帧被作为一个四元组存储,使用spherical linear interpolation(这应该怎么译?译者也不清楚).函数D3DXQuaternionSlerp可以实现这种插值.下面的X文件模板被用于存储动画.
AnimationKey
这个模板用于存储动画关键帧码.这个模板的每一个实例都包含帧码的类型(位置,缩放,转动,矩阵)和帧码数组.数组中的每一个元素包含帧码的值和一个DWORD型的值指出帧的持续时间.
Animation
这个模板存储特定的动画帧码,它应该至少包含一个AnimationKey模板,也应该有一个指向目标帧的指针.
AnimationSet
用于作为Animation模板的一个容器.在这个集合里面的Animation模板有同样的持续时间值.
实现动画
为了实现skin mesh,我们将需要增加一个新的类.我们把这个类命名为CAnimationNode.这个类拥有帧码和指向目标帧的指针.这个类也同样包含一个SetTime函数.这个函数会用从AnimationKey得到的的新的时间值更新目标帧的变换矩阵.CAnimationNode的每 一个实例将拥有Animation模板的一个实例.下面这个图显示出代码的新的设计:
CSkinMesh::Create()
Begin
Initialize X file API
Register D3DRM templates
Open the X file
For every top level template in the X file
Begin
Retrieve the X file data object
Pass the data object to RootFrame.Load
End
Link the bones to the skin mesh(es)
Link the bones to the animations
End
CFrameNode::Load()
Begin
Check the type of the data object
If the type is Mesh
Begin
Create new CMeshNode object
Attach the new object to the frame
Pass the data object to CMeshNode::Create of the new mesh
End
Else if type is FrameTransformationMatrix
Load the transformation matrix
Else if type is Frame
Else if type is Animation
Instruct CSkinMesh to load the new animation
Begin
Create new CFrameNode object
Attach the new object to this frame
Set the name of the child frame to the name of the template
For every child template of the current
Begin
Retrieve the X file data object
Pass it to newframe.Load
End
End
End
CSkinMesh::LoadAnimation()
Begin
Create new CAnimationNode object
Attach the new object to the link list
For every child template
Call CAnimationNode::Load for the new animation object
End
CAnimationNode::Load()
Begin
Check the type of the data object
If the type is a reference
Begin
Get the referenced template, which is a frame template
Get the name of it
Store the name
End
Else if type is data
Begin
Check the type of the animation key
Load the key accordingly
End
End
这个SetTime函数就是展现动画能力地方. CSkinMesh::SetTime 简单地调用动画对象的SetTime函数.
CAnimationNode::SetTime()
Begin
If a matrix key is available
Begin
Get the nearest matrix to the given time
Set it to the target frame
End
Else
Begin
Prepare an identity matrix called TransMat
If a scale key is available
Begin
Calculate the accurate scale value
Prepare a scale matrix for this scale value
Append the matrix to TransMat
End
If a rotation key is available
Begin
Calculate the accurate rotation quaternion
Prepare a rotation matrix from this value
Append the matrix to TransMat
End
If a position key is available
Begin
Calculate the accurate position value
Prepare a matrix for it
Append the matrix to TransMat
End
Set TransMat to the target frame
End
End
现在你已经了解了所有与skin mesh相关的东西了.是时候去下载代码并自己分析它的了. 注意,源码为清晰起见,已经被简单化了,省去了许多错误检测代码.代码假定你的电脑上有3D加速卡,以及你的系统支持blending weights.对于一个更为复杂的示例,你应该参考DX8 SDK.SDK上面有很多indexed和non-indexed的顶点混合的检测和实现.