DirectX9 3D 快速上手 4

接下来我们要使用Mesh读入.X文件,关于.X文件,其实可以说很多,我们可以用外部的工具例如3DS MAX来建立.3ds文件,然后利用微软提供给我们的工具转换成.X文件,如果你同时会用3DS你也许会问,那材质怎么办? 你不用担心,.X文件能自动的包含材质,和动画,所以利用Mesh我们可以方便的八我们在3DS MAX的做品用在游戏中。

.X文件允许自定义的扩展,当然这个我们在以后的内容也会讲到,我们先看怎么使用,顺便提一句,还有一种用得比较多的文件格式.Md3格式的文件,也就是Quake3使用的文件,如果有机会我也会讲到。

关于3DS文件和.X转换可以参看GameRes网站的文章http://www.gameres.com/Articles/Program/Visual/3D/3DinApp.htm

 

接下来的过程简单的让你无法相信,请看:

        private Mesh mesh = null; //建立Mesh对象

        private Material[] meshMaterials;  //用于保存材质

        private Texture[] meshTextures;   //用于保存纹理

        private void LoadMesh(string file)

        {

            ExtendedMaterial[] mtrl; //保存Mesh子集信息,保存Material信息

            // 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);

                    }

                }

            }

        }

如果你觉得这里代码比较混乱,没有关系,我们来理一理,首先要说的是Mesh类还有两个主要的静态方法可以加载外部模型。这两个方法分别是Mesh.FormFile和Mesh.FromStream。两个方法本质上来说都是一样的,stream方法有更多的重载以适应不同大小的流。Mesh.FormFile最简单,我们就先只介绍这个,这个方法有很多重载的版本,我们用的是参数最多的一个,这样其他的也都好理解了:

public static Mesh FromFile(
    string filename, //文件名
    MeshFlags options,// 控制着去哪里以及如何加载数据
    Device device,// 渲染mesh的device
    out GraphicsStream adjacency,//保存每个面相邻的3个面
    out ExtendedMaterial materials,// 保存了普通的Direct3D材质和一个加载为纹理的字符串,常是使用的纹理或资源文件名
    out EffectInstance effects //描述了用于mesh的HLSL材质文件和值。
);

我们使用的是一个有4参数的方法:

public static Mesh FromFile(
    string filename,
    MeshFlags options,
    Device device,
    out ExtendedMaterial materials
);

接下来,如果读入的这个.X文件有材质或者纹理,就根据材质和纹理的大小建立数组以保存这些纹理和材质。因为mesh中可能有许多不同的子集,所以需要分别创建一个材质和纹理的数组以满足每一个子集的需要。Mesh会自动地把每一个子集和这些子集的材质纹理一一对座。

这样我们就完成了一个LoadMesh函数,这个函数我们可以用在以后任何需要读入.X文件的地方,十分的方便。

下面我们来看看我们的成果,当然我们还需要在绘图的地方加几句:

            for (int i = 0; i < meshMaterials.Length; i++)

            {

                device.Material = meshMaterials[i];// 把保存的材质赋予device;

                device.SetTexture(0, meshTextures[i]);// 把纹理赋予device,如果没有就为Null

                mesh.DrawSubset(i);// 根据子集的ID调用DrawSubset方法

            }

好了,现在我们可以在以往的框架的基础上编译一下了,我们可以看到已经读入了一个.X文件,不管怎么样 都是值得庆贺的。我们再看看SDK Tutorial6的例子后,发现这个程序的结果可以旋转,其实也很好实现,我们只需要设置一下旋转矩阵就可以了,就像上一张我们讲的那样,在上面那段for前面加上一句就可以了:

device.Transform.World = Matrix.RotationYawPitchRoll(yaw, pitch, roll) * Matrix.Translation(x, y, z);

好了这样我们也就达到目的了,你也可以随自己的意思设置变换矩阵,很COOL吧?

好了,下面是完整的代码,如果大家有什么意见,发到我的blog上吧。大家一起进步。

 

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using Microsoft.DirectX;

using Microsoft.DirectX.Direct3D;

 

namespace Chapter5Code

{

     /// <summary>

     /// Summary description for Form1.

     /// </summary>

     public class Form1 : System.Windows.Forms.Form

     {

        private Device device = null;

        private Mesh mesh = null;

        private Material[] meshMaterials;

        private Texture[] meshTextures;

 

         /// <summary>

         /// Required designer variable.

         /// </summary>

         private System.ComponentModel.Container components = null;

        private float angle = 0.0f;

 

         public Form1()

         {

              //

              // Required for Windows Form Designer support

              //

              InitializeComponent();

 

            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);

         }

 

        /// <summary>

        /// We will initialize our graphics device here

        /// </summary>

        public void InitializeGraphics()

        {

            // Set our presentation parameters

            PresentParameters presentParams = new PresentParameters();

 

            presentParams.Windowed = true;

            presentParams.SwapEffect = SwapEffect.Discard;

            presentParams.AutoDepthStencilFormat = DepthFormat.D16;

            presentParams.EnableAutoDepthStencil = true;

 

            // Create our device

            device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);

 

            // Load our mesh

            LoadMesh(@"..\..\tiny.x");

        }

 

        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);

                    }

                }

            }

        }

 

        private void SetupCamera()

        {

            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1.0f, 10000.0f);

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

            //device.RenderState.Ambient = Color.DarkBlue;

            device.Lights[0].Type = LightType.Directional;

            device.Lights[0].Diffuse = Color.White;

            device.Lights[0].Direction = new Vector3(0, -1, -1);

            device.Lights[0].Update();

            device.Lights[0].Enabled = true;

 

        }

 

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)

        {

            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue, 1.0f, 0);

 

            SetupCamera();

 

            device.BeginScene();

 

            // Draw our Mesh

            DrawMesh(angle / (float)Math.PI, angle / (float)Math.PI * 2.0f, angle / (float)Math.PI / 4.0f, 0.0f, 0.0f, 0.0f);

 

            device.EndScene();

 

            device.Present();

 

            this.Invalidate();

        }

 

        private void DrawMesh(float yaw, float pitch, float roll, float x, float y, float z)

        {

            angle += 0.01f;

 

            device.Transform.World = Matrix.RotationYawPitchRoll(yaw, pitch, roll) * Matrix.Translation(x, y, z);

            for (int i = 0; i < meshMaterials.Length; i++)

            {

                device.Material = meshMaterials[i];

                device.SetTexture(0, meshTextures[i]);

                mesh.DrawSubset(i);

            }

        }

 

        /// <summary>

         /// Clean up any resources being used.

         /// </summary>

         protected override void Dispose( bool disposing )

         {

              if( disposing )

              {

                   if (components != null)

                   {

                       components.Dispose();

                   }

              }

              base.Dispose( disposing );

         }

 

         #region Windows Form Designer generated code

         /// <summary>

         /// Required method for Designer support - do not modify

         /// the contents of this method with the code editor.

         /// </summary>

         private void InitializeComponent()

         {

              this.components = new System.ComponentModel.Container();

              this.Size = new Size(800,600);

              this.Text = "Form1";

         }

         #endregion

 

         /// <summary>

         /// The main entry point for the application.

         /// </summary>

        static void
Main
()

        {

            using (Form1 frm = new Form1())

            {

                // Show our form and initialize our graphics engine

                frm.Show();

                frm.InitializeGraphics();

                Application.Run(frm);

            }

        }

     }

}

其实我们都已经发现,到目前为止我们的程序都是遵循一个固定的框架,有时候你发现程序很长,其实从框架角度来看,就没那么长了,怕看长代码的人可以注意一下,同时很多代码都是通用的。下次学习怎么操控Mesh。

By sssa2000

时间: 2024-11-16 05:31:44

DirectX9 3D 快速上手 4的相关文章

DirectX9 3D 快速上手 5

DirectX9 3D 快速上手  5By sssa2000     这一章的内容相对很简单,控制Mesh的移动,旋转等等,其实这一切都是在对矩阵进行操作.在 DX中,用到的变换有3种,一种是基于Word坐标系的,一种是基于View坐标系的,还有一种是基于投影的变换.而这些变换都是通过矩阵的运算来实现的,在.Net的托管环境下,实现这些操作相对于非托管来说简单一写,不用对矩阵的每个值运算. 关于矩阵的运算和变换的关系,很多文章都有分析,GameRes也有很多这样的好文章,例如:http://de

DirectX9 3D快速上手 3

DirectX9 3D快速上手 3 By sssa2000 4/15/2005 我们这里暂时先跳过,乏味的索引缓冲和深度缓冲的内容,先看看怎么在3D空间中实现一个东西,给自己来点成就感. 正好SDK的向导也是这么安排的,呵呵,那我们就继续从向导出发吧,以Tutorial 3为例子. 这个例子主要讲解运用变换矩阵来实现物体的变换,学过图形学或者线性代数的肯定就很容易理解,没学过的,找点这方面的资料看看就可以了. 先看看这个例子实现了什么,编译运行,噢,相比前面两个例子,有耳目一新的感觉,一个三角形

DirectX9 3D 快速上手 6

讲了很多,最基础的部分就剩下纹理没有讲到了.Texture是Directx里面非常重要的一部分.为了简便起见,我们还是以SDK的Tutorial5为例子. 纹理就像一张墙纸,用来贴在物体的表面,当然,如果足够大,贴一次就能覆盖整个物体的表面,也可以用适当的方法让纹理排列成你要的效果. 来看看纹理的比较重要的函数:Device.SetTexture public void SetTexture(    int stage, //纹理混合阶段序号,从0开始    BaseTexture textur

DirectX9 3D 快速上手 7

这里我想继续写点和Mesh有关的东西,毕竟我们可能还需要对它有很多别的要求.在3D游戏的实际运用中,一般来说都是运用低多边形模型,简称低模.这样才能有更加好的速度来运行游戏,恰好DX中有提供给我们这样的函数让我们来控制读入的Mesh的复杂程度. public void WeldVertices ( Microsoft.DirectX.Direct3D.WeldEpsilonsFlags flags ,//标志     Microsoft.DirectX.Direct3D.WeldEpsilons

DirectX9 3D 快速上手 8

 上一次中途结束了本来应该讲到的控制Mesh的细节程度的方法的,这一次补上.我们这里使用的是简单的方法,并没有涉及到场景剔出等等复杂的方法,我这里主要还是用DX9提供给我们的类库,progressive meshe.progressive meshes主要的优点就是允许我们控制顶点和面的数目,这样我们就可以灵活的控制mesh细节的显示程度.和Mesh一样,progressive meshe也都是继承自BaseMesh这个类.比较重要的属性主要有2个NumberFaces和NumberVertic

19条小技巧让你快速上手Ubuntu 11.04

Ubuntu 11.04在4月底正式发布了,新版本首次采用Unity界面,很多操作和GNOME都不相同,也许你在使用过程中会出现手足无措,不过新鲜事物总是要花费一段时间适应,之后你会发现Ubuntu 11.04还是很不错的. 下面我们为大家收集了19个小技巧,能让你快速上手Ubuntu 11.04,新手们不妨看看: 1.不喜欢Unity?切换到Ubuntu GNOME经典桌面 注销unity桌面环境,然后选择登录环境为"经典桌面"即可进入. 若是你喜欢Unity,可是你的显卡不给力3D

Win8强大兼容性无需适应快速上手

  如果说使用Win7是在一个我们熟悉的环境中操作,那么Win8就是给我们带来了两个激动人心的环境,一个是新颖的"开始"屏幕及它的应用生态,还有一个就是我们熟悉的跟Win7一样的桌面系统.这也就意味着Win8具有很强的兼容性,可以毫不费力地运行Win7的程序,轻松上手无压力. 其实一个操作系统做到Windows这样,基本也不用太多的在意兼容性问题了.作为一个使用最广泛的操作系统,任何软件厂商都会千方百计地向其靠拢,以便能在新系统上运行它们的程序,这是一个向上兼容的过程. Win8不仅仅

Eclipse快速上手Hibernate--4. 继承映射(3)

继承     前两篇文章<Eclipse快速上手Hibernate--4. 继承映射(1) >和<继承映射(2)>中已经谈了每个类层次结构一个表(table per class hierarchy)与每个子类一个表(table per subclass)的策略,这篇文章主要说的是每个具体类一个表(table per concrete class).一些重复的部分这里就不说了,请参考前两篇文章.    这个策略很简单,抽象的基类不参与映射,具体子类参与映射.  1. 创建项目 · 

Eclipse快速上手Hibernate--4. 继承映射(1)

继承    前面的<Eclipse快速上手Hibernate--1. 入门实例 >等三篇文章已经谈了Hibernate的入门以及利用工具创建的方法.这篇文章主要说说在Hibernate中的继承映射.相关配置请参考前三篇文章.    如果程序中的对象含有继承的关系,在Hibernate中有以下三种策略将这种关系映射到数据表上:· 每个类层次结构一个表(table per class hierarchy)· 每个子类一个表(table per subclass) · 每个具体类一个表(table