11.4.1 载入动画模型

本节你将创建一个叫做AnimatedModel的用于实时处理骨骼动画模型的类,这个类包含载入模型,播放和更新动画,绘制模型的方法,AnimatedModel类中开始时先声明变量。

动画模型以XNA Model的形式被载入,它有一个dictionary,此dictionary包含一个可以通过Tag属性访问的AnimatedModelData对象。通过这种方式,Model类包含了模型的网格和effect,而AnimatedModelData包含模型的骨骼和动画。你声明了类型为Model的model变量和类型为AnimatedModelData的animatedModel变量,你将模型的变换信息存储在一个类型为Transformation的变量中。

Model model;
AnimatedModelData animatedModelData;
Transformation transformation; 		

你还需要声明一些变量处理如何重建动画。你需要存储当前播放的动画、当前帧和动画的时间。你声明activeAnimation变量存储当前播放的动画,activeAnimationKeyframeIndex和activeAnimationTime存储当前动画帧和时间:

AnimationData activeAnimation;
int activeAnimationKeyframe; 
TimeSpan activeAnimationTime;		

你还需要声明两个变量用来设置动画速度和开启动画循环——enableAnimationLoop animationSpeed:

bool enableAnimationLoop; 
float animationSpeed; 		

当模型正在进行动画时,你使用一些临时矩阵数组用来计算骨骼bone的最后配置。因为bone的配置是作为一个动画改变的,所以你要声明bone变量存储每个bone的本地配置。你还要声明bonesAbsolute变量存储每个bone的绝对配置,这个配置由bone数组计算得出,用在实时动画中。最后你应声明bonesAnimation变量存储每个bone的最后变换,这个变换用于将顶点放置到bone的坐标系统内,并使用每个bone的绝对配置使它们动起来。我们会在“骨骼动画公式”一节中详细解释细节。

Matrix[] bones; 
Matrix[] bonesAbsolute; 
Matrix[] bonesAnimation; 

要能把自定义变换作用到bone上,你还要声明一个矩阵数组。你可以独立于动画使用自定义变换改变骨骼的bone。例如,你可以对角色骨骼的脖子bone作用一个自定义的旋转:

Matrix[] bonesTransform; 

最后,你需要声明两个变量存储动画模型的effect和材质:

AnimatedModelEffect animatedModelEffect; 
LightMaterial lightMaterial; 

你创建了AnimatedModelEffect类封装了模型的effect,可以使用第8章中创建的LightMaterial类设置它。

载入动画模型

动画模型是作为一个XNA Model存储的,所以第一步是使用素材管理器载入一个XNA Model,然后你需要检查这个模型是否是动画模型-是否在模型的Tag属性中包含一个拥有AnimatedModelData对象的dictionary。

model = Game.Content.Load<Model>( GameAssetsPath.MODELS_PATH + modelFileName); 
// Get the dictionary 
Dictionary<string, object> modelTag =(Dictionary<string, object>)model.Tag; 
if (modelTag == null) 
    throw new InvalidOperationException("This is not a valid animated model."); 
// Get the AnimatedModelData from the dictionary 
if (modelTag.ContainsKey("AnimatedModelData")) 
    animatedModelData = (AnimatedModelData)modelTag["AnimatedModelData"]; 
else 
    throw new InvalidOperationException("This is not a valid animated model."); 		

载入模型后,你需要初始化一些用来设置和重新生成动画的变量。默认模型动画被设置为AnimatedModelData对象中的动画序列的第一个,它被存储在activeAnimation变量中:

if (animatedModelData.Animations.Length > 0) 
    activeAnimation = animatedModelData.Animations[0]; 		

当前动画关键帧和时间被存储在对应的activeAnimationKeyframe和activeAnimationTime变量中,最后你通过animationSpeed变量设置动画的速度。

// Default animation configuration 
animationSpeed = 1.0f; 
activeAnimationKeyframe = 0; 
activeAnimationTime = TimeSpan.Zero; 		

当模型正在进行动画时,你使用一些临时矩阵数组用来计算每个bone的最后配置。这里你需要创建一个矩阵数组,数组长度应该等于bone的数量。你应该使用存储在AnimatedModelData中的bone配置初始化bone数组,用单位矩阵初始化bonesTransform数组。

// Temporary matrices used to animate the bones 
bones = new Matrix[animatedModelData.BonesBindPose.Length]; 
bonesAbsolute = new Matrix[animatedModelData.BonesBindPose.Length]; 
bonesAnimation = new Matrix[animatedModelData.BonesBindPose.Length]; 

// Used to apply custom transformation over the bones 
bonesTransform = new Matrix[animatedModelData.BonesBindPose.Length]; 
for (int i= 0; i< bones.Length; i++)
{
    bones[i] = animatedModelData.BonesBindPose[i]; 
    bonesTransform[i] = Matrix.Identity; 
} 

最后,你获取模型的effect,并把它封装在AnimatedModelEffect中:

// Get the animated model effect - Shared by all meshes 
animatedModelEffect = new AnimatedModelEffect(model.Meshes[0].Effects[0]); 

// Create a default material 
lightMaterial = new LightMaterial(); 		

注意绘制模型的effect也被所有的模型网格共享,下面是AnimatedModel类的Load方法的代码:

public void Load(string modelFileName)
{
    if (!isInitialized) 
         Initialize(); 
    model = Game.Content.Load<Model>( GameAssetsPath.MODELS_PATH + modelFileName); 
    
    // Get the dictionary 
    Dictionary<string, object> modelTag =(Dictionary<string, object>)model.Tag;
    if (modelTag == null) 
        throw new InvalidOperationException( "This is not a valid animated model."); 
    // Get the AnimatedModelData from the dictionary 
    if (modelTag.ContainsKey("AnimatedModelData")) 
        animatedModelData = (AnimatedModelData)modelTag["AnimatedModelData"]; 
    else
        throw new InvalidOperationException("This is not a valid animated model."); 
    
    // Default animation 
    animationSpeed = 1.0f; 
    activeAnimationKeyframe = 0; 
    activeAnimationTime = TimeSpan.Zero; 
    
    if (animatedModelData.Animations.Length > 0)
        activeAnimation = animatedModelData.Animations[0]; 
    // Temporary matrices used to animate the bones 
    bones = new Matrix[animatedModelData.BonesBindPose.Length]; 
    bonesAbsolute = new Matrix[animatedModelData.BonesBindPose.Length]; 
    bonesAnimation = new Matrix[animatedModelData.BonesBindPose.Length]; 
    
    // Used to apply custom transformation over the bones 
    bonesTransform = new Matrix[animatedModelData.BonesBindPose.Length]; 
    for (int i= 0; i< bones.Length; i++)
    {
        bones[i] = animatedModelData.BonesBindPose[i]; 
        bonesTransform[i] = Matrix.Identity; 
    }
    
    // Get the animated model effect - Shared by all meshes 
    animatedModelEffect = new AnimatedModelEffect(model.Meshes[0].Effects[0]); 
    
    // Create a default material 
    lightMaterial = new LightMaterial(); 
}

发布时间:2009/5/6 9:35:11  阅读次数:6396

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

沪ICP备18037240号-1

沪公网安备 31011002002865号