一、 所用基础知识:
(1)关于创建设备
Device类是DirectX里的所有绘图操作所必须的。可以把这个类假想为真实的图形卡。场景里所有其他图形对象都依赖于device。客户端可以有一个到几个device,可以控制任意多个device。
Device共有三个构造函数,最常用的一个如下:
public Device(int adapter,DeviceType deviceType,Control renderWindow, CreateFlags behaviorFlags, PresentParameters[] presentationParameters);
首先来看第一个参数的意思:它表示我们将要使用哪个物理图形卡。计算机里的所有图形卡都有一个唯一的适配器标识符,默认的显卡总是标识为0 的图形卡。
第二个参数:DeviceType,告诉了DirectX3D要创建哪种类型的device。最常用的值是DeviceType.Hardware,表示将创建一个硬件设备。也可以选择DeviceType.Reference,这种设备允许使用“参考光栅器”(reference rasterizer),所有的效果由DirectX3D运行时来实现,速度较慢。应该仅在调试或测试显卡不支持的特性时使用这个选项。
第三个参数表示把设备绑定到的窗口。因为windows form控件类都包含了一个窗口句柄(windows handle),所以很容易把一个确定的类作为渲染窗口。可以使用picturebox、panel或其他任意的控件作为这个参数的值。本例用form。
第四个参数用来描述设备创建之后的行为。大部分CreateFlags枚举的成员都能组合起来使用,使设备具有多种行为。但有一些flag是相互排斥的。本例使用SoftwareVertexProcessing标志。这个标志适合于所有顶点处理都用CPU计算的情况。
最后一个参数,它表示你的设备把数据呈现到显示器的方式。Presentation Parameter类的外观都可以由这个类来控制。
para.Windowed = true;表示以窗口模式运行,另外还可以全屏方式运行。
para.SwapEffect用于控制缓存交换的行为。如果选择了SwapEffect.Flip,运行时会创建额外的后备缓冲(back buffer),并且在显示时拷贝front buffer。SwapEffect.Copy与Flip相似,但要求把后备缓冲设为1。SwaoEffect.Discard是指如果缓冲没有准备好被显示,则会丢弃缓冲中的内容
二、 设备的Clear()方法:
在本例中会有这样一行代码:
device.Clear( ClearFlags.Target, Color.Black , 1.0f, 0 );
使用Clear()方法把窗口填充为实心的颜色。它的第一个参数指定了要填充的对象;在例子里,填充的即是目标窗口。第二个参数是我们所要填充的颜色。其他的两个参数先暂时忽略。在device被填充之后,必须更新显示:Present方法会为完成这个任务。
所以,在完成之后,会有这么一行代码:
device.Present();
三、顶点:
在本例中,使用TransformedColored结构来保存顶点结构,这个结构告诉DirectX3D运行时三角不需要进行坐标变换(比如旋转或移动),因为已经指定了使用屏幕坐标系。它也包含了每一个点(顶点)的颜色的信息。
Vector4结构是保存这种信息最方便的方式。Vector4其实就是(x,y,z,w)经过变换后成为(x/w,y/w,z/w)。然后设置点的颜色。本例中使用标准颜色的ToArgb方法。
二、实例过程:
(1):新建工程,加入引入,并导入名称空间。在工程中新添加一个类:Tree.cs
(2):在Tree类中,定义设备对象变量,并在构造函数中,设置要显示的设备:
private Device displayDevice; //需要显示在哪个设备上。
public Tree(ref Device device)
{
displayDevice = device;
}
(3)添加一个Render()方法,传入一个参数定义生成树的位置,长和宽。接下来利用顶点绘制三角形,形成一棵树:
public void Render(Rectangle rec)
{
CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[15];
verts[0].Position = new Vector4( rec.X+rec.Width*3/6, rec.Y , 0.5f, 1.0f );
verts[0].Color =Color.Green.ToArgb();
verts[1].Position = new Vector4( rec.X+rec.Width*4/6, rec.Y+rec.Height/4, 0.5f, 1.0f );
verts[1].Color =Color.Green.ToArgb();
verts[2].Position = new Vector4( rec.X+rec.Width*2/6, rec.Y+rec.Height/4, 0.5f, 1.0f );
verts[2].Color =Color.Green.ToArgb();
verts[3].Position = new Vector4( rec.X+rec.Width*3/6, rec.Y+rec.Height/4-rec.Height/8, 0.5f, 1.0f );
verts[3].Color =Color.Green.ToArgb();
verts[4].Position = new Vector4(rec.X+rec.Width*5/6, rec.Y+rec.Height*2/4, 0.5f, 1.0f );
verts[4].Color =Color.Green.ToArgb();
verts[5].Position = new Vector4(rec.X+rec.Width/6, rec.Y+rec.Height*2/4, 0.5f, 1.0f );
verts[5].Color =Color.Green.ToArgb();
verts[6].Position = new Vector4( rec.X+rec.Width*3/6, rec.Y+rec.Height*2/4-rec.Height/8, 0.5f, 1.0f );
verts[6].Color =Color.Green.ToArgb();
verts[7].Position = new Vector4(rec.X+rec.Width, rec.Y+rec.Height*3/4, 0.5f, 1.0f );
verts[7].Color =Color.Green.ToArgb();
verts[8].Position = new Vector4(rec.X, rec.Y+rec.Height*3/4, 0.5f, 1.0f );
verts[8].Color =Color.Green.ToArgb();
verts[9].Position = new Vector4(rec.X+rec.Width*2/6, rec.Y+rec.Height*3/4, 0.5f, 1.0f );
verts[9].Color =Color.Maroon.ToArgb();
verts[10].Position = new Vector4(rec.X+rec.Width*4/6, rec.Y+rec.Height, 0.5f, 1.0f );
verts[10].Color =Color.Maroon.ToArgb();
verts[11].Position = new Vector4(rec.X+rec.Width*2/6, rec.Y+rec.Height, 0.5f, 1.0f );
verts[11].Color =Color.Maroon.ToArgb();
//
verts[12].Position = new Vector4(rec.X+rec.Width*2/6, rec.Y+rec.Height*3/4, 0.5f, 1.0f );
verts[12].Color =Color.Maroon.ToArgb();
verts[13].Position = new Vector4(rec.X+rec.Width*4/6, rec.Y+rec.Height*3/4, 0.5f, 1.0f );
verts[13].Color =Color.Maroon.ToArgb();
verts[14].Position =new Vector4(rec.X+rec.Width*4/6, rec.Y+rec.Height, 0.5f, 1.0f );
verts[14].Color =Color.Maroon.ToArgb();
displayDevice.VertexFormat = CustomVertex .TransformedColored .Format;
displayDevice.DrawUserPrimitives( PrimitiveType.TriangleList, 5, verts );
}
(4):回到窗口代码,声明变量:
private Device device = null;
private Tree[] myTree=new Tree[10] ;
Rectangle rec;
在这里,声明了树数组,表示要生成10棵树。
(5)在图形的初始化函数里:进行设备的初始化,并创建设备,其含义前面已经介绍了,接着对树对象进行实例化。
public void InitializeGraphics()
{
PresentParameters para = new PresentParameters();
para.Windowed = true;
para.SwapEffect = SwapEffect.Discard ;
device = new Device( 0, DeviceType.Hardware, this , CreateFlags.HardwareVertexProcessing, para );
for(int i=0;i<10;i++)
{
myTree[i] = new Tree(ref device);
}
}
(6)、在Render()方法中先将背景设置为黑色,然后,生成不同位置,不同大小的树木,形成森林。
public void Render()
{
device.Clear( ClearFlags.Target, Color.Black , 1.0f, 0 );
device.BeginScene();
rec=new Rectangle(100,200,100,100);
myTree[0].Render(rec);
rec= new Rectangle(200,400,200,100);
myTree[1].Render(rec);
rec=new Rectangle(100,300,130,150);
myTree[2].Render(rec);
rec= new Rectangle(300,330,200,200);
myTree[3].Render(rec);
rec=new Rectangle(400,150,80,150);
myTree[4].Render(rec);
rec= new Rectangle(190,400,80,50);
myTree[5].Render(rec);
rec=new Rectangle(150,190,40,80);
myTree[6].Render(rec);
rec= new Rectangle(300,400,90,90);
myTree[7].Render(rec);
rec=new Rectangle(220,30,10,100);
myTree[8].Render(rec);
rec= new Rectangle(10,400,40,40);
myTree[9].Render(rec);
device.EndScene();
device.Present();
this.Invalidate();
}
(7)主函数是这的:
static void Main()
{
using ( Form1 frm = new Form1() )
{
frm.InitializeGraphics();
frm.Show();
while(frm.Created)
{
frm.Render();
Application.DoEvents();
}
frm.Dispose();
}
}
三、 运行程序:
结果如下: