一、创建设备
本节介绍的示例为DirectX SDK自带的示例,在这里将其解释一下,本示例什么也不做,只是显示一个空白窗体。
现在先看程序运行的主函数:
static void Main()
{
//建立一个窗体实例;
using (CreateDevice frm = new CreateDevice())
{
//如果窗体实例创建成功,那么对Direct3D进行初始化
if (!frm.InitializeGraphics())
{
//如果未能进行初始化,则显示一个错误消息,并返回退出程序;
MessageBox.Show("Could not initialize Direct3D. This tutorial will exit.");
return;
}
//如果成功进行初始化,则显示窗体;
frm.Show();
// 如果窗体处于运行状态,则一直执行frm.Render();
while(frm.Created)
{
frm.Render();
Application.DoEvents();
}
}
}
因为这个程序主要是为创建一个界面,因此主要的函数为frm.InitializeGraphics(),下面看它的代码:
public bool InitializeGraphics()
{
try
{
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;
}
}
注意,程序事先已定义了一个全局变量device,它是在DirectX里的Device类,是所有绘图操作所必须的,相当于我们机器里的图形卡,图形对象都依赖于所定义的这个类,其实,可以设置多个device。
代码
PresentParameters presentParams = new PresentParameters();
是一组参数,用来设置设备把数据呈现在显示器的方式。比如,接下来的下面语句的设置
presentParams.Windowed=true;表示我们的程序是全屏显示还是窗口显示。
下面的参数设置用于控制缓存交换的行为。在这里选取的这个选项表示,如果缓冲没能准备好显示,那么就丢弃缓冲区中的数据;另外一外有用的选项是SwapEffect.Flip,如果选择了这个选项,那么在运行时会创建一个额外的缓冲区,并且在显示把缓冲区的内容拷贝到前景中。
presentParams.SwapEffect = SwapEffect.Discard;
接下来的代码是构造device:
device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
构造函数的第一个参数表示将使用哪个物理图形卡,通常个人机器内只装有一个图形卡,但对于专业人员则就不一定了。这样如果机器内有两块图形卡,就可以用0或1来区分开是用哪块图形卡,默认的显卡表示为0的图形卡;
第二个参数,为设备的类型,现在选用的是创建一个硬件设备,但如果有时我们的显卡不支持某种功能时,可以选择DeviceType.Reference;
第三个参数是表示把设备绑定到哪个对象上,可以是整个窗体,或者是窗体上的一个控件,在这里选择是整个窗体。
第四个参数描述的是创建之后的行为。这些枚举成员可以组合起来使用,使设备具有多种行为。在本程序中使用的适合于所有顶点处理都用CPU计算。显然,比所有顶点都用GPU计算要慢一些。
第五个参数表示把数据显示出来的方式,前面已经说过了。
至此,图形的初始化工作完成,接下来当程序运行时,当界面发生变化时,会执行OnPaint()函数。
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
this.Render();
}
在这里面,执行this.Render();现在再来看看这个函数都做了哪些工作。
private void Render()
{
//如果设备没有创建成功,则返回
if (device == null)
return;
//使用兰色填充背景
device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);
//开始绘图。
device.BeginScene();
//以后我们的绘图工作都在这里完成;
device.EndScene();
device.Present();
}
二、创建一个三角形
接下来,我们往场景是添加一个三角形,此示例的完整代码也可以在SDK中找到。
绘一个三角形很简单,只需三个点就可以了,为什么是三角形而不是四边形、五边形的原因是,大家都知道,“不在同一直线上的三点决定一个平面”,因此利用大量三角形可以组合成3D世界里的芸芸众生。当然也可以使用四边形来做,但处理的工作量显然加大了。
为了保存点数据,在这里使用Direct3D名称空间的CustomVertex类,来存储顶点坐标,
代码是:
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[],这种顶点类型为带有颜色无变换的顶点类型,带有颜色很好理解,无变换后面会介绍到它。
程序另外一部分代码是创建顶点缓冲区,后面会介绍到它。
在Render()函数中:
device.VertexFormat = CustomVertex.TransformedColored.Format;
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
表示我们会绘制一系列三角形,顶点为顶点缓冲区中从0开始,第三个参数1表示只绘制一个三角形;
三、创建其它图形
在绘三角形时,使用的是device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
如果给出6个顶点,可以绘2个三角形,分别用顶点(0,1,2),(3,4,5);
绘一个三角形,其实还可以绘制其它各种图形;
首先将程序中顶点个数设置为4个,
CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[4];
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();
verts[3].X=10;verts[3].Y=200;verts[3].Z=0.5f; verts[3].Rhw=1; verts[3].Color = System.Drawing.Color.Aqua.ToArgb();
stm.Write(verts);
同时顶点缓冲区也更改为4:
vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 4, dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);
将绘制图元的代码更改为:
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0,2);
三角形带是一系列相连的三角形,每两个相邻的三角形共享两个顶点。剔除模式会自动翻转所有偶数个三角形,因为相邻的三角形共享两个顶点,它们会被翻到反方向。这也是复杂的3D对象使用的最多的图元类型。
执行结果为:
也就是说,如果给定一系列点,绘制三角形采用的顶点是(0,1,2)、(1,2,3)……
注意:在初始化图形函数中加入以下代码:
device.RenderState.CullMode = Cull.None;
如果代码是:
device.DrawPrimitives(PrimitiveType.TriangleFan, 0,2);
执行结果为:
这种方法三角形共用一个顶点,也就是说,如果给定一系列点,绘制三角形采用的顶点是(0,1,2)、(0,2,3)、(0,3,4)……
如果代码是:
device.DrawPrimitives(PrimitiveType.LineList, 0,2);
执行结果是:
把每一对点作为单独的直线来绘制。使用时至少需要有两个顶点。