DirectX9 3D 快速上手 8

原创 2005年05月04日 03:37:00

DirectX9 3D 快速上手 8

By sssa2000

5/4/2005

 

 

上一次中途结束了本来应该讲到的控制Mesh的细节程度的方法的,这一次补上。

我们这里使用的是简单的方法,并没有涉及到场景剔出等等复杂的方法,我这里主要还是用DX9提供给我们的类库,progressive meshe

progressive meshes主要的优点就是允许我们控制顶点和面的数目,这样我们就可以灵活的控制mesh细节的显示程度。

Mesh一样,progressive meshe也都是继承自BaseMesh这个类。比较重要的属性主要有2NumberFacesNumberVertices。从字面我们就可以看出两个属性的含义。

有了前面的基础在使用progressive mesh上也变得十分的简单,首先我们需要声明一个progressive mesh的变量,然后我们看看progressive mesh的构造函数:

public ProgressiveMesh(
    Mesh mesh,
    GraphicsStream adjacency,
    GraphicsStream vertexWeights, //
顶点的权值,越高越不容易被剔出,如果设为null就全部被设为1
    int minValue, //
设定被简化的最小值
    MeshFlags options
);

以下就是核心的代码:

private void LoadMesh(string file)

{

    ExtendedMaterial[] mtrl;

    GraphicsStream adj;

 

    // Load our mesh

    using(Mesh mesh = Mesh.FromFile(file, MeshFlags.Managed, device,

                out adj, 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,微软的SDK也有一个例子,不过那个例子太过于庞大,大部分都是在处理UI方面,真正涉及到progressiveMesh的部分还是很少的。

以下是代码的事例图和完整代码:

这个例子里可以切换线框渲染模式和实体作色模式。

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 progressiveMesh

{

     /// <summary>

     /// Summary description for Form1.

     /// </summary>

     public class Form1 : System.Windows.Forms.Form

     {

        private Device device = null;

        private ProgressiveMesh progressiveMesh = null;

        private Material[] meshMaterials;

        private Texture[] meshTextures;

 

 

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

        private float cameraPos = 8.0f;

        private const int MoveAmount = 2;

 

 

        /// <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(@"../../SprintRacer.x");

 

 

            // Create our font

            font = new Microsoft.DirectX.Direct3D.Font(device, new System.Drawing.Font

                ("Arial", 14.0f, FontStyle.Bold | FontStyle.Italic));

        }

 

 

        private void LoadMesh(string file)

        {

            ExtendedMaterial[] mtrl;

            GraphicsStream adj;

 

 

            // Load our mesh

            using(Mesh mesh = Mesh.FromFile(file, MeshFlags.Managed, device,

                        out adj, 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(CleanType.Simplification ,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;

                }

            }

        }

 

 

        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, cameraPos),

                new Vector3(), new Vector3(0,1,0));

 

 

            device.RenderState.Ambient = Color.Blue;

            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.Blue , 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);

 

 

            font.DrawText(null, string.Format("Number vertices in mesh: {0}",

                ((BaseMesh)progressiveMesh).NumberVertices), new Rectangle(10, 10, 0, 0),

                DrawTextFormat.NoClip, Color.BlanchedAlmond);

 

 

            font.DrawText(null, string.Format("Number faces in mesh: {0}",

                ((BaseMesh)progressiveMesh).NumberFaces), new Rectangle(10, 30, 0, 0),

                DrawTextFormat.NoClip, Color.BlanchedAlmond);

 

 

            device.EndScene();

 

 

            device.Present();

 

 

            this.Invalidate();

        }

 

 

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

        {

            angle += 0.11f;

 

 

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

                progressiveMesh.DrawSubset(i);

            }

        }

        protected override void OnKeyPress(KeyPressEventArgs e)

        {

            if (e.KeyChar == '+')

            {

                cameraPos += (MoveAmount * 2);

                progressiveMesh.NumberVertices =

                    ((BaseMesh)progressiveMesh).NumberVertices - MoveAmount;

 

 

                progressiveMesh.NumberFaces =

                    ((BaseMesh)progressiveMesh).NumberFaces - MoveAmount;

            }

            if (e.KeyChar == '-')

            {

                cameraPos -= (MoveAmount * 2);

                progressiveMesh.NumberVertices =

                    ((BaseMesh)progressiveMesh).NumberVertices + MoveAmount;

 

 

                progressiveMesh.NumberFaces =

                    ((BaseMesh)progressiveMesh).NumberFaces + MoveAmount;

            }

            if (e.KeyChar == 'w')

                device.RenderState.FillMode = FillMode.WireFrame;

 

 

            if (e.KeyChar == 's')

                device.RenderState.FillMode = FillMode.Solid;

        }

 

 

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

            }

        }

     }

}

 

这里我们已经实现了能自由控制显示的细节问题,通过progressiveMesh 我们可以很方便的完成这一点,接下来,顺着这个话题我们来讨论一下如何增加细节的显示程度,也就是说我们将要把读入的Mesh的细节程度增多。这里我们部探讨原理,因为我数学也是很差,我们可以借助Patch Meshes 来实现。

Patch Meshes通过增加读入的Mesh的顶点来对细节程度进行增加。

public PatchMesh(ID3DXPatchMesh); 这就是PathMesh的构造函数,只要传入一个读入的Mesh就可以了。接下来我们将用一个例子展示怎么增加显示的细节程度

private void CreatePatchMesh(string file, float tessLevel)

{

    if (tessLevel < 1.0f) //如果小于默认的值,不再增加,直接返回

        return;

 

    if (mesh != null)

        mesh.Dispose();

 

    using (Mesh tempmesh = LoadMesh(file))

    {

        using (PatchMesh patch = PatchMesh.CreateNPatchMesh(tempmesh))

        {

            // Calculate the new number of faces/vertices

            int numberFaces = (int)(tempmesh.NumberFaces

                * Math.Pow(tessLevel, 3));

            int numberVerts = (int)(tempmesh.NumberVertices

                * Math.Pow(tessLevel, 3));

 

            mesh = new Mesh(numberFaces, numberVerts, MeshFlags.Managed

                | MeshFlags.Use32Bit, tempmesh.VertexFormat, device);

 

            // Tessellate the patched mesh

            patch.Tessellate(tessLevel, mesh); //tessLevel的基础上把mesh分成小方格

        }

    }

}

 

private Mesh LoadMesh(string file)

{

……………………….

if ((mesh.VertexFormat & VertexFormats.Normal) != VertexFormats.Normal)

//如果没有法线信息,就要计算法线,发现信息会在上面的Tessellate方法中被用到。

    {

        // We must have normals for our patch meshes

        Mesh tempMesh = mesh.Clone(mesh.Options.Value,

            mesh.VertexFormat | VertexFormats.Normal, device);

 

        tempMesh.ComputeNormals();

 

        mesh.Dispose();

        mesh = tempMesh;

    }

    return mesh;

}

 

以下就是运行的图例

可以明显地看出,我们的程序还是有明显的效果的,不过对于增加的细节,程序将变得十分的缓慢。

以下是全部的代码:

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 PathMesh

{

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

 

 

        private float tessLevel = 1.0f;

        private const float tessIncrement = 1.0f;

        private string filename = @"../../sphere.x";

 

 

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

 

 

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

 

 

            // Create our patch mesh

            CreatePatchMesh(filename, tessLevel);

 

 

            // Create our font

            font = new Microsoft.DirectX.Direct3D.Font(device, new System.Drawing.Font

                ("Arial", 14.0f, FontStyle.Bold | FontStyle.Italic));

 

 

            // Default to wireframe mode first

            device.RenderState.FillMode = FillMode.WireFrame;

        }

 

 

        /// <summary>

        /// Creates a temporary mesh object, and a patch mesh from it

        /// </summary>

        /// <param name="file">The original mesh to use</param>

        /// <param name="tessLevel">The tesselation level</param>

        private void CreatePatchMesh(string file, float tessLevel)

        {

            if (tessLevel < 1.0f) // Nothing to do

                return;

 

 

            if (mesh != null)

                mesh.Dispose();

 

 

            using (Mesh tempmesh = LoadMesh(file))

            {

                using (PatchMesh patch = PatchMesh.CreateNPatchMesh(tempmesh))

                {

                    // Calculate the new number of faces/vertices

                    int numberFaces = (int)(tempmesh.NumberFaces

                        * Math.Pow(tessLevel, 3));

                    int numberVerts = (int)(tempmesh.NumberVertices

                        * Math.Pow(tessLevel, 3));

 

 

                    mesh = new Mesh(numberFaces, numberVerts, MeshFlags.Managed

                        | MeshFlags.Use32Bit, tempmesh.VertexFormat, device);

 

 

                    // Tessellate the patched mesh

                    patch.Tessellate(tessLevel, mesh);

                }

            }

        }

 

 

        /// <summary>

        /// Load a mesh from a file and return it

        /// </summary>

        /// <param name="file">The file to load</param>

        /// <returns>The created mesh</returns>

        private Mesh LoadMesh(string file)

        {

            ExtendedMaterial[] mtrl;

 

 

            // Load our mesh

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

                    }

                }

            }

 

 

            if ((mesh.VertexFormat & VertexFormats.Normal) != VertexFormats.Normal)

            {

                // We must have normals for our patch meshes

                Mesh tempMesh = mesh.Clone(mesh.Options.Value,

                    mesh.VertexFormat | VertexFormats.Normal, device);

 

 

                tempMesh.ComputeNormals();

 

 

                mesh.Dispose();

                mesh = tempMesh;

            }

            return mesh;

        }

 

 

        private void SetupCamera()

        {

            device.Transform.Projection = Matrix.PerspectiveFovLH(

                (float)Math.PI / 4, this.Width / this.Height, 1.0f, 100.0f);

 

 

            device.Transform.View = Matrix.LookAtLH(new Vector3(0,0, 5.0f),

                new Vector3(), new Vector3(0,1,0));

 

 

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

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

            device.Lights[0].Direction = new Vector3(0, 0, -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);

 

 

            font.DrawText(null, string.Format

                ("Number Vertices: {0}/r/nNumber Faces: {1}",

                mesh.NumberVertices, mesh.NumberFaces),

                new Rectangle(10,10,0,0),

                DrawTextFormat.NoClip, Color.Black);

 

 

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

            }

        }

        protected override void OnKeyPress(KeyPressEventArgs e)

        {

            if (e.KeyChar == '+')

            {

                tessLevel += tessIncrement;

                CreatePatchMesh(filename, tessLevel);

            }

            if (e.KeyChar == '-')

            {

                tessLevel -= tessIncrement;

                CreatePatchMesh(filename, tessLevel);

            }

            if (e.KeyChar == 'c')

            {

                filename = @"../../cube.x";

                tessLevel = 1.0f;

                CreatePatchMesh(filename, tessLevel);

            }

            if (e.KeyChar == 'o')

            {

                filename = @"../../sphere.x";

                tessLevel = 1.0f;

                CreatePatchMesh(filename, tessLevel);

            }

            if (e.KeyChar == 't')

            {

                filename = @"../../tiger.x";

                tessLevel = 1.0f;

                CreatePatchMesh(filename, tessLevel);

            }

            if (e.KeyChar == 'w')

                device.RenderState.FillMode = FillMode.WireFrame;

 

 

            if (e.KeyChar == 's')

                device.RenderState.FillMode = FillMode.Solid;

 

 

        }

 

 

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

            }

        }

     }

}

 

 

 

 

By sssa2000

5/4/2005

相关文章推荐

Directx3D9学习之二:Windows编程之最简单窗口程序

Directx3D9学习之二:Windows编程之最简单窗口程序 一、一些基本知识介绍 由于D3D的编程要借助于windows的窗口来体现,所以也需要懂一些windows的编程知识(以前做得比较多的是...
  • lhqsine
  • lhqsine
  • 2015年01月31日 23:05
  • 2657

DirectX9 初始化Direct3D通用框架

初始化Direct3D通用框架 The declaration of IDirect3DDevice9::Clearis: HRESULTIDirect3DDevice9::Clear( DWORD...

DirectX 9 UI设计学习笔记之三:第4章Introducing DirectInput+第5章Wrapping Direct3D

此文由哈利_蜘蛛侠原创,转载请注明出处!有问题欢迎联系本人!        邮箱:2024958085@qq.com          上一期的地址: DX 9 UI设计学习笔记之二  ...

3d世界尽在掌握!—— directx 8.1/9 graphic 全解析

前言:  在我们日常游戏中,很多朋友经常挂在嘴边一个:directx。.几乎100%的喜欢玩游戏,特别是fps 3d射击游戏的朋友都要遇到directx安装和设置的问题。不过,很遗憾的是,有超过70%...

DirectX_9_3D游戏设计入门.pdf

  • 2014年07月15日 11:03
  • 4.4MB
  • 下载

windows phone 8 xaml/directx3d 切后台纹理未释放导致内存泄漏的问题

先说明情况,我们的引擎未采用cocos2dx,而是用的开源的

DirectX 9.0c游戏开发手记之“龙书”第二版学习笔记之6: Chap8: Drawing in Direct3D ---- Part II

从这一章起,龙书第二版正式进入了shader部分了!利用HLSL语言编写各种shader的内容贯穿此书的大半部分,而且是最令人激动的部分了!用shader可以实现很多用非shader技术难以实现或者根...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:DirectX9 3D 快速上手 8
举报原因:
原因补充:

(最多只允许输入30个字)