4.6 缩放模型
问题
当从磁盘载入模型时,往往会太大或太小,你想将模型缩放到定义的大小。
解决方案
首先你需要定义一个模型的全局包围球,前面一个教程已经解释了。知道了这个包围球,你就可以知道模型的当前尺寸了。从这个尺寸,你可以知道需要将模型放大或所小多少。你也可以将这个缩放操作储存在root Bone矩阵中,这样缩放会施加到模型中所有Bone的所有矩阵上(可见教程4-9)。
工作原理
通常,你使用的模型是由不同的工具制作的,或从网上下载的,你无法指定模型的大小。所以,如果你能将模型缩放到你想要的大小那会很棒。
下面的代码计算模型需要缩放到多少,这需要存储在模型Tag属性中的全局包围球(见前一个教程)。
private Matrix[] AutoScale(Model model, float requestedSize) { BoundingSphere bSphere = (BoundingSphere)model.Tag; float originalSize = bSphere.Radius * 2; float scalingFactor = requestedSize / originalSize; model.Root.Transform = model.Root.Transform * Matrix.CreateScale(scalingFactor); Matrix[] modelTransforms = new Matrix[model.Bones.Count]; model.CopyAbsoluteBoneTransformsTo(modelTransforms); return modelTransforms; }
你需要将模型传递给这个方法指定最终的模型有多大。这个方法一开始获取一个模型的全局包围球,你需要将求的半径乘2获取球的大小,对应于模型的初始大小。接下来,你将requestedSize除以这个值获取这个模型需要缩放到多大。你可以使用这个缩放因子创建一个矩阵,将这个矩阵作为绘制模型时的世界矩阵,这样你的模型就会缩放到想要的大小了。
在Root Bone上施加缩放
构建良好的模型将所有子网格链接到它们的root bone。这意味着当你缩放了root bone矩阵 (见教程4-9),所有ModelMeshes也会自动缩放。你可以通过将Root矩阵乘以缩放矩阵实现,在前面计算的scalingFactor基础上,将这个结果矩阵存储在模型中。因为你改变了Bone矩阵的内容,所以你必须提取modelTransforms矩阵的新版本。
注意:更好的方法是在自定义模型处理器中使用一个可以进行配置的变量,见教程4-12学习如何扩展默认模型处理器。
代码
在LoadContent方法中,你需要使用两行代码加载并缩放模型:
myModel = XNAUtils.LoadModelWithBoundingSphere(ref modelTransforms, "tank", Content); modelTransforms = AutoScale(myModel, 10.0f);
当绘制模型时,你可以使用普通的代码,因为缩放信息已经被储存在模型的Root bone中了。通过这种方式,每次当你调用Model. CopyAbsoluteBoneTransformsTo方法时,所有的结果矩阵都已经包含了缩放操作,这样在将模型的各个部分绘制到屏幕之前它们已经进行了缩放。
Matrix worldMatrix = Matrix.Identity; myModel.CopyAbsoluteBoneTransformsTo(modelTransforms); foreach (ModelMesh mesh in myModel.Meshes) { foreach (BasicEffect effect in mesh.Effects) { effect.EnableDefaultLighting(); effect.World = modelTransforms[mesh.ParentBone.Index] * worldMatrix; effect.View = fpsCam.ViewMatrix; effect.Projection = fpsCam.ProjectionMatrix; } mesh.Draw(); }
记住,你可以在教程4-1和4-9中找到关于Bone的更多信息,在教程4-2中找到世界矩阵的更多信息。
发布时间:2009/8/29 上午10:26:33 阅读次数:5904