处理模型——通过扩展模型处理器直接处理每个ModelMesh的顶点位置数据
问题
前面的教程中让你可以访问模型的所有顶点的相对于模型初始位置的位置。但是,如果你想对模型的一部分施加动画,例如,旋转一个人的手臂,那么你还想变换手臂,手,手指的位置。使用上一个教程的结果是不可能的,因为Vector3集合不包含Vector3属于模型哪个部分的信息,只包含相对于模型初始位置的信息。
解决方案
模型的独立变换部分是存储在ModelMeshe中的。ModelMesh有一个Tag属性,你可以在Tag中存储有用的信息。在本教程中,你将在Tag属性中存储ModelMesh的所有顶点的位置信息。
你将存储相对于ModelMesh初始位置的顶点位置信息(而不是像前一个教程中的相对于模型的初始位置)。当XNA程序更新Bone矩阵并计算绝对矩阵时(见教程4-9),你可以使用与渲染模型相同的绝对Bone矩阵变换位置,获得相对于模型初始位置的顶点位置。相对于前一个教程,这个方法最大的好处是,这次你将处理独立部分的当前变换。工作原理这个教程在前一个教程的基础上再加以扩展。你仍需要遍历模型的整个结构,但这次,无需将所有顶点存储在一个大数组中,你将为每个节点生成独立的数组。
在遍历了整个模型并存储了数组后,你使用默认模型处理器从节点产生一个ModelContent。最后,你遍历ModelContent中的所有ModelMeshContents,然后在对应的ModelMeshContent的Tag属性中存储每个数组。
注意:ModelContent对象是内容处理器的输出,然后它被写入一个二进制文件。当程序运行时,这个文件从磁盘被加载,这个对象被转换为一个模型。
以下是处理器的开始部分的代码:
public override ModelContent Process(NodeContent input,ContentProcessorContext context) {List<Vector3[]> modelVertices = new List<Vector3[]>(); modelVertices = AddModelMeshVertexArrayToList (input, modelVertices); }
你创建了一个集合存储独立的Vector3数组,然后,将这个集合和根节点传递到AddModelMeshVertexArrayToList方法。
这个方法首先调用自己,传递它的子节点,这样可以将子节点的数组添加到集合中。
当所有子节点的数组添加到集合之后,AddModelMeshVertexArrayToList方法检查当前节点是否包含顶点。如果包含,则创建一个包含所有顶点位置的Vector3数组并将它添加到集合中。
private List<Vector3[]> AddModelMeshVertexArrayToList(NodeContent node, List<Vector3[]>modelVertices) {foreach (NodeContent child in node.Children) modelVertices = AddModelMeshVertexArrayToList(child, modelVertices); MeshContent mesh = node as MeshContent; if (mesh != null) {List<Vector3> nodeVertices = new List<Vector3>(); foreach (GeometryContent geo in mesh.Geometry) {foreach (int index in geo.Indices) {Vector3 vertex = geo.Vertices.Positions[index]; nodeVertices.Add(vertex); }}modelVertices.Add(nodeVertices.ToArray()); }return modelVertices; }
注意:与上一个教程相反,这次位置不进行变换。这是因为你想存储相对于ModelMesh初始位置的顶点位置,而不是相对于模型初始位置。你可以在以后通过ModelMesh的绝对矩阵转换它们。
注意:AddModelMeshVertexArrayToList方法与上一个教程的AddVerticesToList方法最主要的不同之处在于:你在添加当前节点的数据之前首先将子节点的数据添加到集合中。在前一个教程中在添加子节点的数据之前首先添加当前节点的数据,这样看起来可能更加直观。但是,以ModelMesh保存到模型的相同顺序将ModelMesh的数组保存是很重要的,这样你可以很容易地在Process方法的最后加载数组。
最后,将下列代码添加到Process方法的最后:
ModelContent usualModel = base.Process(input, context); int i = 0; foreach(ModelMeshContent mesh in usualModel.Meshes) mesh.Tag = modelVertices[i++]; return usualModel;
有了数组后,你就可以使用默认模型处理器从节点创建一个默认的ModelContent对象。在每个ModelMeshes中你存储了正确的包含Vector3的数组。
但是,别忘了有些ModelMeshe是由超过一个ModelMeshPart构成的,每个ModelMeshPart 有自己的NodeContent,对于每个ModelMeshPart,AddModelMeshVertexArrayToList方法会将Vector3数组添加到集合。所以要让代码完整,你需要用以下代码替代前面的代码:
ModelContent usualModel = base.Process(input, context); int i = 0; foreach (ModelMeshContent mesh in usualModel.Meshes) {List<Vector3> modelMeshVertices = new List<Vector3>();foreach (ModelMeshPartContent part in mesh.MeshParts) { modelMeshVertices.AddRange(modelVertices[i++]); } mesh.Tag = modelMeshVertices.ToArray(); } return usualModel;
对于属于一个ModelMesh的所有ModelMeshPart,上面的代码将所有Vector3添加到一个集合,这个集合被转换到一个数组并存储在ModelMesh的Tag属性中。
注意:因为一个ModelMesh的所有ModelMeshPart使用相同的绝对变换矩阵,你可以一次性地处理所有Vector3仍能保证正确处理动画(见教程4-9)。你可能还想在ModelMeshPart 的Tag属性中存储每个ModelMeshPart的顶点,例如,创建一个更好的包围球处理快速的碰撞检测。
最后返回ModelContent,做好了串行化为一个二进制文件的准备。
当你使用自定义模型处理器导入一个模型时,你可以在模型的每个ModelMesh的Tag属性中找到一个数组,这个数组包含了ModelMesh的每个三角形的三个Vector3分量。在 LoadContent方法中加载模型:
myModel = Content.Load<Model>("tank"); modelTransforms = new Matrix[myModel.Bones.Count];
现在每个模型的ModelMesh的Tag属性中包含了Vector3的集合,你可以通过编译器访问储存在数组中的数据:
Vector3[] modelVertices = (Vector3[])myModel.Meshes[0].Tag; System.Diagnostics.Debugger.Break();
最后一行代码放置了一个断点,你可以观察Vector3的内容。
代码
下面是自定义内容管道:
namespace Vector3Pipeline {[ContentProcessor]public class ModelVector3Processor : ModelProcessor{public override ModelContent Process(NodeContent input, ContentProcessorContext context) {List<Vector3[]> modelVertices = new List<Vector3[]>(); modelVertices = AddModelMeshVertexArrayToList(input, modelVertices); ModelContent usualModel = base.Process(input, context); int i = 0; foreach (ModelMeshContent mesh in usualModel.Meshes) {List<Vector3> modelMeshVertices = new List<Vector3>(); foreach (ModelMeshPartContent part in mesh.MeshParts) {modelMeshVertices.AddRange(modelVertices[i++]); }mesh.Tag = modelMeshVertices.ToArray(); }return usualModel; }private List<Vector3[]> AddModelMeshVertexArrayToList(NodeContent node, List<Vector3[]> modelVertices){foreach (NodeContent child in node.Children) modelVertices = AddModelMeshVertexArrayToList(child, modelVertices); MeshContent mesh = node as MeshContent; if (mesh != null) {List<Vector3> nodeVertices = new List<Vector3>(); foreach (GeometryContent geo in mesh.Geometry) {foreach (int index in geo.Indices) {Vector3 vertex = geo.Vertices.Positions[index]; nodeVertices.Add(vertex); }}modelVertices.Add(nodeVertices.ToArray()); } return modelVertices; }} }
转载于:https://www.cnblogs.com/AlexCheng/archive/2011/01/16/2120129.html
处理模型——通过扩展模型处理器直接处理每个ModelMesh的顶点位置数据相关推荐
- 扩展 junit 框架_JUnit 5 –扩展模型
扩展 junit 框架 我们已经对Java最普遍的测试框架的下一个版本了解很多. 现在,让我们看一下JUnit 5扩展模型,该模型将允许库和框架将自己的实现添加到JUnit中. 总览 建立 基本 建筑 ...
- JUnit 5 –扩展模型
我们已经对Java最普遍的测试框架的下一个版本了解很多. 现在让我们看一下JUnit 5扩展模型,该模型将允许库和框架将自己的实现添加到JUnit中. 总览 设定 基本 建筑 扩展模型 条件 注射 - ...
- BERT-QE:用于文档Rerank的上下文化查询扩展模型
BERT-QE 论文名称:EMNLP2020 | BERT-QE: Contextualized Query Expansion for Document Re-ranking arxiv地址:htt ...
- 第13章 二叉树模型及其扩展
这学期会时不时更新一下伊曼纽尔·德曼(Emanuel Derman) 教授与迈克尔B.米勒(Michael B. Miller)的<The Volatility Smile>这本书,本意是 ...
- 中台背景下的多端自适应的业务扩展模型架构实践
前言 随着数字化变革的持续深入和中台战略的落地,越来来越多的最佳实践涌现出来,这里我不在赘述什么是数字化转型和什么是中台,这里我分享一下我们在中台建设中的一些顶层思考和实践.在中台规划之前中我一直在思 ...
- Actor模型与传统模型
官方链接 小结: 本文从传统面向对象的封装,内存共享以及并发错误处理等几个方面对比了传统并发模型的缺陷. 对象封装在并发的情况下很难保证原子性,加锁又会导致性能问题,还会导致死锁 多核CPU在cach ...
- 3维线程格 gpu_GPU的线程模型和内存模型
遇见C++ AMP:在GPU上做并行计算 Written by Allen Lee I see all the young believers, your target audience. I see ...
- 模型转换、模型压缩、模型加速工具汇总
点击上方"计算机视觉工坊",选择"星标" 干货第一时间送达 编辑丨机器学习AI算法工程 一.场景需求解读 在现实场景中,我们经常会遇到这样一个问题,即某篇论 ...
- 1.2 《数据库系统概论》之数据模型(概念模型、逻辑模型--物理模型、层次模型、网状模型、关系模型、面向对象模型、对象关系模型)
文章目录 0.思维导图 1.数据模型的概念 2.两大类数据模型 客观对象的抽象过程---两步抽象 3.数据模型的组成要素 (1)数据结构 (2)数据操作 (3)数据的完整性约束条件 4.概念模型 (1 ...
- JAVA 继承内存模型_Java内存模型
JVM的组成 类加载器(classloader) 执行引擎(execution engine) 运行时数据区域(runtime data area) 对于Java程序员来说,在虚拟机自动内存管理机制下 ...
最新文章
- 请收下这份NLP热门词汇解读
- pix4d计算机配置速度,ContextCapture、Pix4D电脑需求配置
- 基于JSP实现医院病历管理系统
- windows自动关闭无响应程序
- 硬盘引导安装windows7系统的方法
- 信息系统项目管理师:第5章:项目范围管理(2)-重点汇总
- [基础题]8.(*)按如下要求编写Java程序:(1)定义一个交通工具收费接口Charge
- B2C和B2B之间有多大差距
- 201671030111 李蓉 实验十四 团队项目评审课程学习总结
- oracle中的service_name,instance_name,db_name,oracle_sid,sid_name的用法及区别(转)
- mysql开通访问权限_mysql 用户远程访问权限开通
- HDU1166树状数组
- Map集合的4种遍历方式
- 145. 大小写转换
- 空间直线与平面的交点
- 利用R绘制venn图(VennDiagram、eulerr、venneuler、limma)
- 办公小技巧1:使用adb命令在电脑与手机之间传输文件
- Win7系统网络连接图标显示红叉但可以正常上网怎么办
- Wifi4更换Wifi6路由器的使用体验
- 男子与 AI 对话 6 周后,选择自杀!一时难分“魔鬼”还是“救星”?