【翻译】Managed DirectX(第九章)

** 第九章 ** ** ** ** 使用其它 ** ** Mesh ** ** 类型 ** **

**

**

**

**

** 翻译:clayman **

** [email protected] **

** 仅供个人学习之用,勿用于任何商业用途,转载请注明作者^_^ **

** 翻译:clayman **

** [email protected] **

** 仅供个人学习之用,勿用于任何商业用途,转载请注明作者^_^ **

**


**

我们花了大量的时间来学习扩展库中的基本 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))

<p class="MsoNormal" style="MARGIN: 0cm 0cm

Published At
Categories with Web编程
Tagged with
comments powered by Disqus