第九章 使用其它Mesh类型

简化Mesh(Simplifying Meshes)
  我们花了大量的时间来学习扩展库中的基本Mesh类,但实际上,还有3种其它Mesh类型我们没有讨论过,在这一章中,我们就来看看这几个对象。
我们已经知道如何通过使用Mesh类的Simplify方法创建一个简化过的mesh。通常情况下,使用简化mesh只是为了显示低细节的模型,但在任何场景中,都不可能为一个mesh储存太多版本,特别是其中的很多版本你可能根本不会用到。

  SimplificationMesh方法可以用来压缩简化mesh的过程。但是,不能直接使用这个对象进行渲染你必须先通过simplification mesh创建一个真正的mesh。还记得先前简化mesh的例子吗,我们在例子里展示了两种情况。一种是在很近的情况下观察未经简化的mesh,另一种则是在比较远的的情况下显示简化了很多面和顶点的mesh。我们将再次做类似工作,不过这一次,我们将逐渐的移动摄像机。

还是以第五章的例子为基础,逐渐添加代码。首先,添加SimplificationMesh对象的声明,同时还有控制摄像机位子的变量:

private SimplificationMesh simplifiedMesh = null;
private float camreaPos = 580.0f;

把摄像机的深度位置作为变量,可以方便以后的修改。接下来更新view transform,让他使用正确的位置信息。在SetupCamera方法中,添加更新如下代码:

device.Transform.View = Matrix.LookAtLH(new Vector3(0,0,cameraPos), new Vector3(), new Vector3(0,1,0));

  显然,由于每一帧都会调用SetupCamera方法,因此任何对camera变量的改变都会马上得到更新,这正是我们想要的效果。SimplifiycationMesh中储存了我们将用于简化的mesh。注意到没,我们没有创建任何额外的Mesh对象。每次简化之后,只需用他代替原来的mesh就可以了。

修改LoadMesh方法确保mesh是经过了clean的,并且正确创建了simplifycationMesh对象。如下修改代码:

private void LoadMesh(string file)
{
ExtendedMaterial[] mtrl;
// Load our mesh
mesh = Mesh.FromFile(file, MeshFlags.Managed, device, out mtrl);
// If we have any materials, store them
if ((mtrl != null) && (mtrl.Length > 0))
{
meshMaterials = new Material[mtrl.Length];
meshTextures = new Texture[mtrl.Length];
// Store each material and texture
for (int i = 0; i < mtrl.Length; i++)
{
meshMaterials[i] = mtrl[i].Material3D;
if ((mtrl[i].TextureFilename != null) && (mtrl[i].TextureFilename != string.Empty))
{
// We have a texture, try to load it
meshTextures[i] = TextureLoader.FromFile(device, @"..\..\" + mtrl[i].TextureFilename);
}
}
}
//Clean our mesh
Mesh tempMesh = Mesh.Clean(mesh,adj,adj);
//replace extsting mesh with this one
mesh.Dispose();
mesh = tempMesh;
//creat simiplification mesh
simplificationMesh = new SimplificationMesh(mesh,adj);
}
(注:新版的MDX中应为Mesh tempMesh = Mesh.Clean(CleanType. Simplification,mesh,adj,adj); 另外,在使用了mesh.Dispose();之后程序有可能会出现异常。)

  如你所见,在clean方法和simplificationMesh方法中都要用到邻接信息。在加载了mesh创建了纹理之后,我们就对mesh进行clean,准备简化。接下来,用clean过的mesh创建simplificationMesh对象。

  事实上,现在不需要做任何修改,也能正确绘制mesh。但是,我们想添加一些代码让摄像机慢慢远离mesh,同时,减少mesh的细节。使用键盘来控制摄像机的移动,添加代码:

protected override void onKeyPress(KeyPressEventArgs e)
{
if(e.KeyChar == '+')
{
cameraPos += (MoveAmount * 2);
simplifiedMesh.ReduceFaces(mesh.NumberFaces - MoveAmount);
simplifiedMesh.ReduceVertices(mesh.NumberVertices - MoveAmount);
mesh.Dispose();
mesh = simplifiedMesh.Clone(simplifiedMesh.Options.value,simplifiedMesh.VertexFormat,device);
}
if(e.KeyChar == 'w')
device.RenderState.FillMode = FillMode.WireFrame;
if(e.KeyChar == 's')
device.RenderState.FillMode = FillMode.Solid;
base.onKeyPress (e);
}

注意到,这里使用了一个统一的常量来控制每次按下按键时移动的总数。你可以根据实际情况来设置这个常量,以下是我使用的值:

private const int MoveAmount = 100;

  在这个方法里,按下W键的时候,跳转为线框模式,这样可以很容易看出实际绘制的三角形。按下S键则跳回填充模式。按下+键,则会使摄像机远离模型。移动摄像机的时候,根据指定的常理来减少mesh的顶点和面。然后释放原来的mesh。使用simplifiedMesh的克隆代替原mesh,并进行渲染。

  现在运行程序,可以使用+键来移动物体,并且在线框模式和填充模式之间转换,但离远了之后,几乎看不出模型是经过简化的。我们再添加一些文本来显示所渲染的面数和顶点数吧。添加字体变量:

private Microsoft.DirectX.Direct3D.Font font = null;

在绘制文本前必须先初始化字体对象,在IntializeGraphics方法的LoadMesh之后,添加代码:

font = new Microsoft.DirectX.Direct3D.Font(device,new System.Drawing.Font("Arial",14.0f,FontStyle.Bold | FontStyle.Italic));

可以根据自己的喜好来改变字体的类型和大小。现在可以绘制字体了。在调用DrawMesh方法之后,添加如下代码:

font.DrawText(null,string.Format("number vertices in mesh: {0}",mesh.NumberVertices),new Rectangle(10,10,0,0),DrawTextFormat.NoClip,Color.BlanchedAlmond);
font.DrawText(null,string.Format("number faces in mesh: {0}",mesh.NumberFaces),new Rectangle(10,30,0,0),DrawTextFormat.NoClip,Color.BlanchedAlmond);

好了,现在可以方便的看到移动模型时顶点和面的数量都减少了。

  这个程序的主要缺点就在于我们不能恢复丢失的顶点。当然,我们可以出色的完成简化任务,但是,当我们需要再次近距离观察模型怎么办呢?没有RaiseVertices方法,调用ReduceVerctices方法,传入一个很大的顶点数也是没有用的。SimplificationMesh就是设计来简化mesh的,仅此而已,不能恢复。ProgressiveMesh对象就是用来处理这个问题的。

使用Progressive Meshes控制细节级别
  有些情况下,你只需要简化mesh。但是,一味的简化,意味着无法再恢复对象的细节,而同时需要简化和增加对象细节的情况确是很常见的。我相信看到这里,你已经知道progressive mesh方法名字的来历了吧。

  为了显示progressiveMesh方法的行为,我们将写一个和上一部分很类似的程序。这一次,我们不但可以简化mesh,还可以在摄像机靠近模型时,添加mesh的细节。还是从第五章的文件开始。

  Progressivemesh类于Mesh类一样,都继承于BaseMesh类。与SimplificationMesh类相比,可以直接用progressiveMesh对象来绘制物体。这样,就可以用以下变量来代替Mesh对象了:

  同样,你应该把原来所有的mesh变量都替换为这个变量。之后,更新LoadMesh方法,因为代码现在不能通过编译了。使用一个类似的方法;我们将在最后创建progressiveMesh对象。添加代码:

private void LoadMesh(string file)
{
ExtendedMaterial[] mtrl;
GraphicsStream adj;
// Load our mesh
using(Mesh mesh = Mesh.FromFile(file, MeshFlags.Managed, device, out mtrl)
{
// If we have any materials, store them
if ((mtrl != null) && (mtrl.Length > 0))
{
meshMaterials = new Material[mtrl.Length];
meshTextures = new Texture[mtrl.Length];
// Store each material and texture
for (int i = 0; i < mtrl.Length; i++)
{
meshMaterials[i] = mtrl[i].Material3D;
if ((mtrl[i].TextureFilename != null) && (mtrl[i].TextureFilename != string.Empty))
{
// We have a texture, try to load it
meshTextures[i] = TextureLoader.FromFile(device, @"..\..\" + mtrl[i].TextureFilename);
}
}
}
//clean our main mesh
using(Mesh tempMesh = Mesh.Clean(mesh,adj,adj)
{
//create our progressive mesh
progressiveMesh = new ProgressiveMesh(tempMesh,adj,null,1,MeshFlags.SimplifyVertex);
//set the initial mesh to the max
progressiveMesh.NumberFaces = progressiveMesh.MaxFaces;
progressiveMesh.NumberVertices = progressiveMesh.MaxVertices;
}
}
}

  注意到我们使用了两个临时Mesh来创建progressiveMesh对象。使用一个clean过的mesh来完成真正的创建。对于progressiveMesh的构造函数来说,第四个参数是最重要的:根据所使用的MeshFlags选项,它是所创建Mesh的顶点或面的最小值。显然,这只是一个近似值,即使不能把mesh简化到这个级别,这个方法还是会成功。

  你应该还注意到,我们马上就把面数和顶点数设置为了最大值。创建mesh并保留在简化状态(generating the mesh leaves it simplified)。设置progressiveMesh中面或顶点数中的任意一个,都可以在渲染时更改mesh的细节。因为我们想初始化时显示所有细节,自然把面和顶点值都设置为最大值。

为了让程序通过编译,还需要修改DrawMesh中的DrawMesh方法:

progressiveMesh.DrawSubset(i);

现在运行程序,可以看到和原来一样的效果。显示了所有细节的模型不停旋转。现在来处理移动摄像机的键盘事件。

~~~~~~~~~~~~~~~~~第八章完~~~~~~~~~~~~~~~~~~

 下载代码

转载于:https://www.cnblogs.com/yurow/articles/951621.html

深入Managed DirectX9(十五)相关推荐

  1. 深入Managed DirectX9

    作者 calyman    clayman_joe@yahoo.com.cn   (超级好的翻译.建议初学者仔细看) 文章来源 >> http://www.cnblogs.com/dago ...

  2. 深入Managed DirectX9(转)作者calyman(超级好的翻译。建议初学者仔细看)

    作者 calyman    clayman_joe@yahoo.com.cn :[翻译]深入Managed DirectX9(一) Device类是DirectX里的所有绘图操作所必须的.可以把这个类 ...

  3. 2021年大数据HBase(十五):HBase的Bulk Load批量加载操作

    全网最详细的大数据HBase文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 HBase的Bulk Load批量加载操作 一.Bulk L ...

  4. 2021年大数据Hadoop(二十五):YARN通俗介绍和基本架构

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 YARN通俗介绍和基本架构 Yarn通俗介绍 Yarn基本 ...

  5. 2021年大数据Hadoop(十五):Hadoop的联邦机制 Federation

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 Hadoop的联邦机制 Federation 背景概述 F ...

  6. 十五天精通WCF——第六天 你必须要了解的3种通信模式

    十五天精通WCF--第六天 你必须要了解的3种通信模式 原文:十五天精通WCF--第六天 你必须要了解的3种通信模式 wcf已经说到第六天了,居然还没有说到这玩意有几种通信模式,惭愧惭愧,不过很简单啦 ...

  7. opengl正方形绕点旋转_一题十五种解法够不够? 旋转,构造,四点共圆乐不停...

    平移,旋转,轴对称是我们初中学习的"几何三大变换".在我们初中阶段学习的几何知识中占据着核心的地位,特别是旋转,那更是核心中的核心(河南中考22题年年考). 如何更好的理解旋转,如 ...

  8. NeHe OpenGL第三十五课:播放AVI

    NeHe OpenGL第三十五课:播放AVI 在OpenGL中播放AVI: 在OpenGL中如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错. ...

  9. 转:中国互联网十五年的22个创新模式

    中国互联网十五年的22个创新模式     今天,看网上有人推荐<沸腾十五年>,讲中国互联网从发源到现今. 有人有如此梳理,自己本来也想梳理一下中国互联网这么多年,到底是哪些公司出来了,为什 ...

  10. 15crmo焊接后多长时间探伤_15CrMo十五铬钼属于合金钢?、下面来解释一下

    15CrMo十五铬钼属于合金钢​,主要用于石油.石化.高压锅炉等,专门用途的无缝管有锅炉用无缝管.地质用无缝钢管及石油用无缝管等多种.​ 一.15CrMo化学成分: C:0.12-0.18 Mn:0. ...

最新文章

  1. 福建农林大学朱方捷组招聘讲师/副教授/助理——生信分析方向
  2. 快速径向对称 只检测暗对称 代码(2)
  3. 场景法设计测试用例atm_测试用例设计经典面试题之电梯、杯子、笔、桌子、洗衣机、椅子、ATM等...
  4. Vbox配置仅主机模式
  5. cobbler的dhcp服务_Cobbler服务器安装部署
  6. 开源开放 | 开源立体化漏洞情报知识图谱(四维创智)
  7. HTTPS 的 7 次握手以及 9 倍时延
  8. vue2.0 keep-alive 缓存页面数据
  9. 关于silverlight打印功能
  10. html遍历1到100,bat for循环100次:循环100求和
  11. 在腾讯云主机上使用URLOS一键安装yoshop萤火虫小程序商城
  12. 如何用ffmpeg给视频打水印
  13. 香港浸会大学计算机学院校友,校友反馈 | 香港浸会大学值不值得去读?
  14. 一个程序猿小小的梦想-写在16年底的时候
  15. Deep Learning 效率神器推荐
  16. Linux 中的逻辑卷 LVM 管理完整初学者指南
  17. java微服务Nacos配置管理
  18. R语言---安装依赖包
  19. 漂亮的梦幻图,可用来做背景图(60张左右)
  20. POI-TL使用及工具类

热门文章

  1. 线程和Application.DoEvents()
  2. js Math对象属性和方法
  3. 最近,前端开发把我恶心着了,为了甩锅,我写了个牛逼的日志切面!
  4. Nginx 的 5 大应用场景,太实用了!
  5. 卸载 Navicat!事实已证明,正版客户端,它更牛逼……
  6. Dubbo 的心跳设计,值得学习!
  7. 讲真,WiFi 6到底6在哪儿
  8. 硬核!尽量避免 bug 手法,让测试彻底失业
  9. 作为面试官,我是怎么快速判断程序员能力的?
  10. 这个锅,运维来背?忘记续期 HTTPS 证书,网易邮箱大量用户无法使用