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 阅读次数:6903