DirectX9 3D 快速上手 4

80酷酷网    80kuku.com

接下来我们要使用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


分享到
  • 微信分享
  • 新浪微博
  • QQ好友
  • QQ空间
点击: