DirectX9 3D 快速上手(转),编写游戏需要的。很不错的初学者教程。

原文:
http://dev.gameres.com/Program/Visual/DirectX/DX93D_1.mht
出自http://www.gameres.com/

DirectX9 3D
快速上手  1

By sssa2000

4/13/2005

  由于项目需要,不得不介入到以前从没有接触过的3D编程,我选择了DX9,当然这也是项目需要,既然是要求快速上手,那么就最好选择RAD的开发工具了,显然用MS的东西比较保险一些,我这个人怕麻烦,最怕出一些莫名其妙的错误了,所以这里C#是比较好的选择了,当然如果你用VB.net的话也不错,反正这两个差不多,个人偏爱C#一些。

  废话少说,切入正题。

    要使用DX,那么第一件事情就是建立设备。比起DirectDraw3D的设备建立还是稍微简单一些的:

public Device (

System.Int32 adapter ,                  //表示我们将要使用哪个物理图形卡。一般用0

Microsoft.DirectX.Direct3D.DeviceType deviceType ,// 创建那种类型的device

System.Windows.Forms.Control renderWindow , // rendrWindow表示把设备绑定到的窗口。

Microsoft.DirectX.Direct3D.CreateFlags behaviorFlags, //描述设备创建之后的行为Microsoft.DirectX.Direct3D.PresentParameters presentationParameters )// 设备把数据呈现到显示器的方式

 

一共5个参数,看一下代码段:

PresentParameters presentParams = new PresentParameters();

                   presentParams.Windowed=true; //窗口模式

                   presentParams.SwapEffect = SwapEffect.Discard;// SwapEffect成员用于控制缓存交换的行为。如果选择了SwapEffect.Flip,运行时会创建额外的后备缓冲

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

 
到这里设备的建立就已经完成了,对于其中相关参数的含义,可以参考DirectX的帮助。

现在看看DX SDK自带的Tutorial1,是不是很容易了?托管环境为我们作了很多事情,不过在这个例子里面没有体现出来,感谢上帝。在这个例子里面Render()是关键。

     private void Render()

         {

              if (device == null)

                   return;

              //Clear the backbuffer to a blue color

              device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

              //Begin the scene

              device.BeginScene();

              // Rendering of scene objects can happen here

              //End the scene

              device.EndScene();

              device.Present();

         }

 

Render是渲染的入口点,每一帧渲染都要调用这个函数。BeginScene()/EndScene()函数对,分别在渲染前后调用。BeginScene()会使系统检查内部数据结构和渲染表面的可用性有效性。这里在BeginScene()/EndScene() 中间没有做任何事情,所以就没有什么被渲染,这个例子可以被当作模板使用。

 

下面是Tutorial1的全部代码:

//-----------------------------------------------------------------------------

// File: CreateDevice.cs

//

// Desc: This is the first tutorial for using Direct3D. In this tutorial, all

//       we are doing is creating a Direct3D device and using it to clear the

//       window.

//

// Copyright (c) Microsoft Corporation. All rights reserved.

//-----------------------------------------------------------------------------

using System;

using System.Drawing;

using System.Windows.Forms;

using Microsoft.DirectX;

using Microsoft.DirectX.Direct3D;

 

namespace DeviceTutorial

{

     public class CreateDevice : Form

     {

         // Our global variables for this project

         Device device = null; // Our rendering device

 

         public CreateDevice()

         {

              // Set the initial size of our form

              this.ClientSize = new System.Drawing.Size(400,300);

              // And it's caption

              this.Text = "D3D Tutorial 01: CreateDevice";

         }

        

         public bool InitializeGraphics()

         {

              try

              {

                   // Now let's setup our D3D stuff

                   PresentParameters presentParams = new PresentParameters();

                   presentParams.Windowed=true;

                   presentParams.SwapEffect = SwapEffect.Discard;

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

                   return true;

              }

              catch (DirectXException)

            {

                return false;

            }

         }

         private void Render()

         {

              if (device == null)

                   return;

 

              //Clear the backbuffer to a blue color

              device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

              //Begin the scene

              device.BeginScene();

             

              // Rendering of scene objects can happen here

   

              //End the scene

              device.EndScene();

              device.Present();

         }

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

         {

              this.Render(); // Render on painting

         }

         protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)

         {

              if ((int)(byte)e.KeyChar == (int)System.Windows.Forms.Keys.Escape)

                   this.Close(); // Esc was pressed

         }

 

         /// <summary>

         /// The main entry point for the application.

         /// </summary>

         static void Main()

         {

 

            using (CreateDevice frm = new CreateDevice())

            {

                if (!frm.InitializeGraphics()) // Initialize Direct3D

                {

                    MessageBox.Show("Could not initialize Direct3D.  This tutorial will exit.");

                    return;

                }

                frm.Show();

 

                // While the form is still valid, render and process messages

                while(frm.Created)

                {

                    frm.Render();

                    Application.DoEvents();

                }

            }

         }

     }

}

DirectX9 3D 快速上手  2

By sssa2000

4/13/2005

按照通用教程,将完了设备的建立,就该讲到Vertices(顶点),当然这也是很重要的概念,不得不学啊。

看看SDKTutorial2,这个例子也很简单在例子1的基础上画了一个三角形,用渐进色填充了一下。如下图:

                                     

首先看看Vertices 怎么建立。

 

CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3];

verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1; verts[0].Color = System.Drawing.Color.Aqua.ToArgb();

verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1; verts[1].Color = System.Drawing.Color.Brown.ToArgb();

verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; verts[2].Color = System.Drawing.Color.LightPink.ToArgb();          

CustomVertex.TransformedColored包含了经过变换的顶点和颜色值的数据,为什么要变换?这个和DX使用的坐标系统有关系。要说的话一两句说清楚也困难,这里使用变换过的顶点,指定坐标就是在屏幕的坐标,很直观,再度感受到RAD的好处。当然CustomVertex还包括了很多其他的结构体,适用于其他的需要,有兴趣的可以去看看。

其中Rhw表示齐次w坐标的倒数,仅仅适用于变换过的顶点。

注意,不同版本的DirectX9 ,语法上会有些不一样,注意参考一下文档,我的是DirectX9.0c (October 2004).

事实上,现在已经可以渲染,但是这个时候的效率比较低。每次渲染场景时,都要分配新的顶点列表,并且所有东西存储在系统内存里。现代显卡集成了足够的显存,把顶点数据存放在显存可以获得大幅的新能提升:存放在系统内存里的数据,渲染每一帧时都要拷贝到显卡,这会带来极大的损失。只有移除每帧时的这种分配才能帮助我们提高性能。

所以我们需要缓冲,于是就有了Vertex Buffers以下是常用的2个构造函数:

  public VertexBuffer( Device device, int sizeOfBufferInBytes, Usage usage, VertexFormats vertexFormat, Pool pool)   

 public VertexBuffer( Type typeVertexType, int numVerts, Device device, Usage usage,VertexFormats vertexFormat, Pool pool);

以下是各参数的意义:

device——用来创建顶点缓冲的device,创建的顶点缓冲只能被这个device使用;
sizeOfBufferInBytes——
所创建的顶点缓冲大小,以字节为单位。使用带有这个参数的构造函数创建的顶点缓冲可以存放任何类型的顶点;
typeVertexType——
如果去要创建的顶点缓冲只储存一种类型的顶点,则使用这个参数。它的值可以是CustomVertex类中的顶点结构类型,也可以是自定义的顶点类型。且这个值不能为null
numVert——
指定了顶点缓冲的储存类型之后,也必须指定缓冲储存的顶点数量最大值。这个值必须大于0
usage——
定义如何使用顶点缓冲。并不会是所有Usage类型的成员都能使用,只有一下几个是正确的参数:DoNotClip,Dynamic, Npatches, Points, PTPatches, SoftwareProcessing, WriteOnly;
vertexFormat——
定义储存在顶点缓冲中的顶点格式。,如果创建的为通用缓冲的话,则使用VertexFormat.None
pool——
定位顶点缓冲使用的内存池位置,可以指定一下几个内存池位置:
  Default Managed SystemMemory Scratch

 

让我们看看在SDK的这个例子里面它是怎么做的:

public void OnCreateDevice(object sender, EventArgs e)

         {

              Device dev = (Device)sender;

              vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);

              vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);

              this.OnCreateVertexBuffer(vertexBuffer, null);

         }

和预期的完全一样,并且,还有添加了一个事件:vertexBuffer.Created,在这个事件里面我们就可以把每个顶点的值写入,就像我们前面写的那样。大家不嫌啰嗦的话我们不妨再看看:

         public void OnCreateVertexBuffer(object sender, EventArgs e)

         {

              VertexBuffer vb = (VertexBuffer)sender;

              GraphicsStream stm = vb.Lock(0, 0, 0);

              CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3];

              verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1; verts[0].Color = System.Drawing.Color.Aqua.ToArgb();

              verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1; verts[1].Color = System.Drawing.Color.Brown.ToArgb();

              verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; verts[2].Color = System.Drawing.Color.LightPink.ToArgb();

              stm.Write(verts);

              vb.Unlock();

         }

为了理解简单,我们可以理解,如果需要使用VertexBuffer就必须使用GraphicsStream 当然,使用IndexBuffer也需要用到它,这个我们后面自然会讲到。

这里为了避免多处同时读写的情况,使用了Lock()这个方法,事实上,在以后很多地方都要接触到这个方法。看看Lock方法的原形:

public GraphicsStream Lock(
    int offsetToLock,//偏移量,设为0表示全部的数据
    int sizeToLock,//设置为0表示全部数据
    LockFlags flags//一般设置为0,当然你也可以由其他的选择,参看SDK文档
);

现在我们已经准备好了一切,现在我们可以来画图了DrawPrimitives将会绘制来自数据流源里的几何体。DrawPrimitives有三个参数

public void DrawPrimitives(
    PrimitiveType primitiveType,//几何体的种类
    int startVertex,// 表示流里的起始顶点
    int primitiveCount//所要绘制的几何体个数
);

下面看看Render()函数

         private void Render()

         {

              if (device == null)

                   return;

              //Clear the backbuffer to a blue color (ARGB = 000000ff)

              device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

              //Begin the scene

              device.BeginScene();

              device.SetStreamSource( 0, vertexBuffer, 0);

              device.VertexFormat = CustomVertex.TransformedColored.Format;//指定格式

              device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);//绘制一个3角形

              //End the scene

              device.EndScene();

              device.Present();

         }

SetStreamSource的作用是让Direct3D绘图的时候读取顶点缓冲。使用这个方法当然是为了配合前面说过的DrawPrimitives()。这个方法有以下两种重载:

public void SetStreamSource(int streamNumber, VertexBuffer streamData, int offsetInBytes, int stride);   

public void SetStreamSource( int streamNumber, VertexBuffer streamData, int offsetInBytes);

两个函数的不同之处在于其中一个多了表示(数据)流步幅大小(stride size of the stream)的参数。

第一个参数是这段数据所使用流的数量。现在,把它设置为0即可;

第二个参数是作为数据源的顶点缓冲,

第三个则是顶点缓冲里需要DirectX绘制的数据的偏移量(以字节为单位)。stride则是缓冲里每一个顶点的大小。如果是用特定类型创建的顶点缓冲,则不需要这个参数。

好了现在可以编译运行了,效果还不错吧。下次我们就要真正的步入3D的世界了。

 

OK,为了方便阅读,附上Tutorial2的完整代码:

//-----------------------------------------------------------------------------

// File: Vertices.cs

//

// Desc: In this tutorial, we are rendering some vertices. This introduces the

//       concept of the vertex buffer, a Direct3D object used to store

//       vertices. Vertices can be defined any way we want by defining a

//       custom structure and a custom FVF (flexible vertex format). In this

//       tutorial, we are using vertices that are transformed (meaning they

//       are already in 2D window coordinates) and lit (meaning we are not

//       using Direct3D lighting, but are supplying our own colors).

//

// Copyright (c) Microsoft Corporation. All rights reserved.

//-----------------------------------------------------------------------------

using System;

using System.Drawing;

using System.Windows.Forms;

using Microsoft.DirectX;

using Microsoft.DirectX.Direct3D;

 

namespace VerticesTutorial

{

     public class Vertices : Form

     {

         // Our global variables for this project

         Device device = null; // Our rendering device

         VertexBuffer vertexBuffer = null;

 

         public Vertices()

         {

              // Set the initial size of our form

              this.ClientSize = new System.Drawing.Size(300,300);

              // And its caption

              this.Text = "Direct3D Tutorial 2 - Vertices";

         }

        

         public bool InitializeGraphics()

         {

              try

              {

                   // Now let's setup our D3D stuff

                   PresentParameters presentParams = new PresentParameters();

                   presentParams.Windowed=true;

                   presentParams.SwapEffect = SwapEffect.Discard;

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

                   this.OnCreateDevice(device, null);

                   return true;

              }

              catch (DirectXException)

            {

                return false;

            }

         }

 

         public void OnCreateDevice(object sender, EventArgs e)

         {

              Device dev = (Device)sender;

              // Now Create the VB

              vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);

              vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);

              this.OnCreateVertexBuffer(vertexBuffer, null);

         }

         public void OnCreateVertexBuffer(object sender, EventArgs e)

         {

              VertexBuffer vb = (VertexBuffer)sender;

              GraphicsStream stm = vb.Lock(0, 0, 0);

              CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3];

 

              verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1; verts[0].Color = System.Drawing.Color.Aqua.ToArgb();

              verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1; verts[1].Color = System.Drawing.Color.Brown.ToArgb();

              verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; verts[2].Color = System.Drawing.Color.LightPink.ToArgb();

              stm.Write(verts);

              vb.Unlock();

         }

         private void Render()

         {

              if (device == null)

                   return;

 

              //Clear the backbuffer to a blue color (ARGB = 000000ff)

              device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

              //Begin the scene

              device.BeginScene();

             

              device.SetStreamSource( 0, vertexBuffer, 0);

              device.VertexFormat = CustomVertex.TransformedColored.Format;

              device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

              //End the scene

              device.EndScene();

              device.Present();

         }

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

         {

              this.Render(); // Render on painting

         }

         protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)

         {

              if ((int)(byte)e.KeyChar == (int)System.Windows.Forms.Keys.Escape)

                   this.Close(); // Esc was pressed

         }

 

         /// <summary>

         /// The main entry point for the application.

         /// </summary>

         static void Main()

         {

 

            using (Vertices frm = new Vertices())

            {

                if (!frm.InitializeGraphics()) // Initialize Direct3D

                {

                    MessageBox.Show("Could not initialize Direct3D.  This tutorial will exit.");

                    return;

                }

                frm.Show();

 

                // While the form is still valid, render and process messages

                while(frm.Created)

                {

                    frm.Render();

                    Application.DoEvents();

                }

            }

         }

 

     }

}

 

DirectX9 3D快速上手 3

By sssa2000

4/15/2005

我们这里暂时先跳过,乏味的索引缓冲和深度缓冲的内容,先看看怎么在3D空间中实现一个东西,给自己来点成就感。

正好SDK的向导也是这么安排的,呵呵,那我们就继续从向导出发吧,以Tutorial 3为例子。

这个例子主要讲解运用变换矩阵来实现物体的变换,学过图形学或者线性代数的肯定就很容易理解,没学过的,找点这方面的资料看看就可以了。

先看看这个例子实现了什么,编译运行,噢,相比前面两个例子,有耳目一新的感觉,一个三角形绕着Y轴旋转。

相比Tutorial 2多了2个函数:OnResetDeviceSetupMatrices。其中有注释,中文由我翻译,E文太差,翻译得不好不要B4我啊

         public void OnResetDevice(object sender, EventArgs e)

         {

              Device dev = (Device)sender;

              // Turn off culling, so we see the front and back of the triangle

//关闭剔除,所以我们可以看见前面的和背面的三角形

              dev.RenderState.CullMode = Cull.None;

              // Turn off D3D lighting, since we are providing our own vertex colors

//关闭灯光,因为我们已经提供了自己的颜色

              dev.RenderState.Lighting = false;

         }

 

         private void SetupMatrices()

         {

              // For our world matrix, we will just rotate the object about the y-axis.

              // Set up the rotation matrix to generate 1 full rotation (2*PI radians)

              // every 1000 ms. To avoid the loss of precision inherent in very high

              // floating point numbers, the system time is modulated by the rotation

              // period before conversion to a radian angle.

 // 在世界坐标中,我们要绕Y旋转,建立旋转矩阵产生每秒360度的旋转,为了避免浮点数中的位数造成的时间上的损失,我们在转变为弧度前,强制调整系统时间

              int  iTime  = Environment.TickCount % 1000;

              float fAngle = iTime * (2.0f * (float)Math.PI) / 1000.0f;

              device.Transform.World = Matrix.RotationY( fAngle );

 

              // Set up our view matrix. A view matrix can be defined given an eye point,

              // a point to lookat, and a direction for which way is up. Here, we set the

              // eye five units back along the z-axis and up three units, look at the

              // origin, and define "up" to be in the y-direction.

//建立观察矩阵,它可以被定义为视点,就像一个摄像机一样。这里我们设置在Z-5Y3的位置

              device.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 3.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) );

 

              // For the projection matrix, we set up a perspective transform (which

              // transforms geometry from 3D view space to 2D viewport space, with

              // a perspective divide making objects smaller in the distance). To build

              // a perpsective transform, we need the field of view (1/4 pi is common),

              // the aspect ratio, and the near and far clipping planes (which define at

              // what distances geometry should be no longer be rendered).

//射影矩阵,我们建立一个透视变换(透视变换把3D空间变换到2D视口,造成透视的效果),为了建立透视变换,我们需要视觉空间,(通常是1/4 pi) 纵横比 和 远距离剔除(远处物体不渲染)

              device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );

         }

 

所有的新东西都在这里了,一共不到10条语句,简单吧?有几点要解释一下。

dev.RenderState.CullMode = Cull.None;

这一句,或许很多人会疑惑,首先了解一下DX的背面剔除功能,和现实中一样,我们同一时间只能够看到一个物体的一面,看不到它的背面,这就是背面剔除。Cull是一个枚举,一共3个值:

CounterClockwise

3

Cull back faces with counterclockwise vertices.

Clockwise

2

Cull back faces with clockwise vertices.

None

1

Do not cull back faces.

如果我们指定了背面剔除的方式,那么我们就看不到物体的背面,这样当三角形转过来的时候我们就看不到转过来的东西,所以设置为none,如果不理解,可以在程序中修改一下这一句话,就能很直观的理解了。

这个例子就这么多内容,当然你也可以把RotateY改为,RotateX, RotateZ等等,可以更加好的理解一下这个例子。

 

 

接下来我们来了解一下Mesh

对我们初学者来说Mesh应该是一个让人激动的东西,让我们来看看介绍:Mesh可以用来储存任何类型的图形数据,但主要用来封装复杂的模型。Mesh类同样也有一些用来提高渲染物体性能的方法。用Mesh你可以从外部文件读入3D的模型例如.3DS文件,这样我们就可以在3D Max中做好模型,然后读入程序,想想看,一个游戏的雏形是不是已经在你脑海了呢?

Mesh对象内部也包含了很多几何体的模型,我们来看看怎么使用它,因为使用它比使用顶点要快捷方便得多,一会你就会深刻体会到。

首先我们要先建立一个Mesh对象    private Mesh mesh = null;

然后mesh = Mesh.Box(device,2.0f,2.0f,2.0f); 这样我们就建立了一个长宽高都为2的立方体,很简单吧?如果你用顶点来建立的话,最快的方法,即使用索引缓冲器,深度缓冲器也要写8个顶点得值,还要SetStreamSource等等繁琐的工作,这一切在Mesh中都替我们完成了。当然,Mesh内置的几何形体还有很多,比如圆柱,茶壶等等,你可以一个一个的试一下。

我们来看看核心的DrawBox函数:

 

this is equivalent

        private void DrawBox(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);

            Material boxMaterial = new Material();

            boxMaterial.Ambient = Color.White; //环境色

            boxMaterial.Diffuse = Color.White; //漫反射

            device.Material = boxMaterial;

            mesh.DrawSubset(0);

        }

先介绍Matrix.RotationYawPitchRoll方法,看看他的原形:

public static Matrix RotationYawPitchRoll(
    float yaw, //
偏移量,即绕Y轴的转动角度
    float pitch,//
斜度,即绕X轴的角度
    float roll//
滚动,即绕Z的角度
);

 

材质(materials描述了这样的一种属性。你可以指定物体如何反射环境光以及散射(diffuse光线,镜面高光(Specular Highlights(少后会讨论它)看起来是什么样,以及物体是否完全反射(emit光线。 这里创建了一个新的材质,它的环境颜色(ambient color(注:环境颜色和环境光的颜色是不同的^_^)和散射颜色值都被设置为白色。使用白色表示它会反射所有的光线。接下来,我们把材质赋予了deviceMaterial属性,这样Direct3D就知道渲染时使用那种材质数据。

这里介绍一点关于光线和色彩的知识:环境色(ambient color,当其为黑色时,表示(环境光)不会影响材质的颜色,当环境色变浅时,它就会照亮材质,并将两种颜色混和起来,从而影响材质的颜色。如何场景中有环境光,那么这些光的颜色和亮度就会控制环境色对于最终材质颜色的影响程度)。把材质改为没有红色成分的颜色(比如绿色)会使物体再次变为黑色(注:因为此时物体不会反射红色,红色的光线被物体全部吸收了),改为含一些红色成分的颜色(比如灰色gray)会使物体呈现深灰色。

Mesh会被分为一系列的子集(subsets)(依据属性缓冲的大小来分配),同时使用一个叫做“DrawSubset”的方法来渲染。使用Mesh类创建的普通图元总是只有一个基于0的子集。所以使用了mesh.DrawSubset(0)

 

下面附上这个例子的全部代码:

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;

 

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

            mesh = Mesh.Box(device, 2.0f, 2.0f, 2.0f);

        }

 

        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, 18.0f), new Vector3(), new Vector3(0,1,0));

            device.RenderState.Ambient = Color.DarkBlue;

 

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

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

            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 boxes

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

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

           // DrawBox(angle / (float)Math.PI, angle / (float)Math.PI * 4.0f, angle / (float)Math.PI / 2.0f, -5.0f, 0.0f, 0.0f);

 

          //  DrawBox(angle / (float)Math.PI, angle / (float)Math.PI * 2.0f, angle / (float)Math.PI / 4.0f, 0.0f, -5.0f, 0.0f);

          //  DrawBox(angle / (float)Math.PI, angle / (float)Math.PI / 2.0f, angle / (float)Math.PI * 4.0f, 5.0f, -5.0f, 0.0f);

          //  DrawBox(angle / (float)Math.PI, angle / (float)Math.PI * 4.0f, angle / (float)Math.PI / 2.0f, -5.0f, -5.0f, 0.0f);

 

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

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

            DrawBox(angle / (float)Math.PI, angle / (float)Math.PI * 4.0f, angle / (float)Math.PI / 2.0f, -5.0f, 5.0f, 0.0f);

 

            device.EndScene();

 

            device.Present();

 

            this.Invalidate();

        }

 

        private void DrawBox(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);

            Material boxMaterial = new Material();

            boxMaterial.Ambient = Color.White;

            boxMaterial.Diffuse = Color.White;

            device.Material = boxMaterial;

            mesh.DrawSubset(0);

        }

 

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

            }

        }

     }

}

不知道大家注意到没有,我注释掉了很多DrawBox函数的调用,你也可以把它改过来,运行看看,你会发现一个问题,就是如果你画9Box和你画一个Box,旋转的速度是不一样的,因为这里并没有像上个例子那样对时间有强制的调整。这个例子里面还有一些是关于灯光的,我们马上就会讲到,其实从字面也可以看出来是什么意思。接下来我们就要去读入我们自己的模型了,激动啊。

原文地址:https://www.cnblogs.com/dagon007/p/149900.html