11.4.4 AnimatedModel的Update方法

在CPU中,你可以将任务分成三个部分以改进模型动画的性能。首先,你需要根据当前播放的动画和时间更新骨骼bone。第二,计算每个bone的绝对坐标。第三,计算用于变换顶点的最终矩阵。你通过计算当前动画时间开始第一步的处理过程。这一步只需将动画时间加上上一次更新以来的elapsed time,而elapsed time还要乘以animation speed因子:

activeAnimationTime += new TimeSpan((long)(time.ElapsedGameTime.Ticks * animationSpeed)); 

然后将当前动画的持续时间与activeAnimationTime比较,检查当前动画是否已经结束,如果已经结束,在重置动画时间后就可以重写开始这个动画:

// Loop the animation 
if (activeAnimationTime > activeAnimation.Duration && enableAnimationLoop) 
{
    long elapsedTicks = activeAnimationTime.Ticks % activeAnimation.Duration.Ticks; 
    activeAnimationTime = new TimeSpan(elapsedTicks); 
    activeAnimationKeyframe = 0; 
} 

然后检查是否是动画的第一次更新。这里你需要将骨骼bone恢复到bind pose:

// Put the bind pose in the bones in the beginning of the animation 
if (activeAnimationKeyframe == 0) 
{
    for (int i= 0; i< bones.Length; i++) 
        bones[i] = animatedModelData.BonesBindPose[i]; 
} 

要重建动画,你需遍历当前模型动画的关键帧,当activeAnimationTime比关键帧时间大时更新模型骨骼bone:

// Read all animation keyframes until the current time is reached 
// That's possible because you have previously sorted the keyframes 
int index = 0; 
Keyframe[] keyframes = activeAnimation.Keyframes; 
while (index < keyframes.Length && keyframes[index].Time <= activeAnimationTime)
{
    int boneIndex = keyframes[index].Bone; 
    bones[boneIndex] = keyframes[index].Transform * bonesTransform[boneIndex]; 
    index++; 
}
activeAnimationKeyframe = index - 1; 

在动画处理的第二部分你需要遍历所有的bone矩阵并计算它们的绝对配置。因为bone数组是根据深度构建的,这个数组中的parent bone不会有一个超过数组索引的索引值。所以你可以按顺序遍历集合中的每个元素,计算它的最终位置(因为它的ancestor的最终位置己经计算好了)。注意数组中的第一个bone已经在绝对坐标系中了(因为它没有parent),但你要使用一个自定义矩阵转换它:

// Fill the bones with their absolute coordinate 
bonesAbsolute[0] = bones[0] * parent; 
for (int i= 1; i< bonesAnimation.Length; i++)
{
    int boneParent = animatedModelData.BonesParent[i]; 
    // Here we are transforming a child bone by its parent 
    bonesAbsolute[i] = bones[i] * bonesAbsolute[boneParent]; 
} 

最后你通过乘以bone中的bind pose中的反变换矩阵计算每个bone的最终位置和当前的绝对位置:

// Before we can transform the mesh's vertices using the calculated 
// bone matrix, we need to put the vertices in the coordinate system 
// of the bone that is linked to it 
for (int i= 0; i< bonesAnimation.Length; i++)
{
    bonesAnimation[i] = animatedModelData.BonesInverseBindPose[i] * bonesAbsolute[i]; 
} 

下面是AnimatedModel类的Update方法代码:

private void UpdateAnimation(GameTime time, Matrix parent)
{
    activeAnimationTime += new TimeSpan((long)(time.ElapsedGameTime.Ticks * animationSpeed)); 
    if (activeAnimation != null) 
    {
        // Loop the animation 
        if (activeAnimationTime >activeAnimation.Duration && enableAnimationLoop) 
        {
            long elapsedTicks = activeAnimationTime.Ticks %activeAnimation.Duration.Ticks; 
            activeAnimationTime = new TimeSpan(elapsedTicks); 
            activeAnimationKeyframe = 0; 
        }
        
        // Every time the animation starts put the local bind pose in 
        // the bones array 
        if (activeAnimationKeyframe == 0) 
        {
            for (int i= 0; i< bones.Length; i++) 
                bones[i] = animatedModelData.BonesBindPose[i]; 
        }
        
        // Play all animation keyframes until the current time 
        // is reached. This is possible because we have sorted the 
        // keyframes by time during the model processing 
        int index = 0; 
        Keyframe[] keyframes = activeAnimation.Keyframes; 
        while (index < keyframes.Length &&keyframes[index].Time <= activeAnimationTime) 
        {
            int boneIndex = keyframes[index].Bone; 
            bones[boneIndex] = keyframes[index].Transform * bonesTransform[boneIndex]; 
            index++; 
            activeAnimationKeyframe = index - 1; 
        }
        
        // Calculate the bones absolute coordinate 
        bonesAbsolute[0] = bones[0] * parent; 
        for (int i= 1; i< bonesAnimation.Length; i++)
        {
            int boneParent = animatedModelData.BonesParent[i]; 
            // Transform the bone configuration by its 
            // parent configuration 
            bonesAbsolute[i] = bones[i] * bonesAbsolute[boneParent]; 
        }
        
        // Before we can transform the vertices we 
        // need to put the vertices in the coordinate system of the 
        // bone that is linked to it 
        for (int i= 0; i< bonesAnimation.Length; i++) 
        {
            bonesAnimation[i] = animatedModelData.BonesInverseBindPose[i] * bonesAbsolute[i]; 
        }
    } 
}

发布时间:2009/5/12 上午8:36:19  阅读次数:5296

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号