Managed DirectX +C# 开发(入门篇)2
sizeOfBufferInBytes——创建的顶点缓冲大小,大小以字节为单位。使用带有这个参数的构造函数创建的顶点缓冲可以存放任何类型的顶点;
typeVertexType——如果要去创建的顶点缓冲只储存一种类型的顶点,则使用这个参数。它的值可以是CustomVertex类中的顶点结构类型,也可以是自定义的顶点类型。这个值不能为null;
numVert——指定缓冲储存的顶点数量最大值。
vertexFormat——在顶点缓冲中的顶点格式,如果创建的为一般缓冲的话,则使用VertexFormat.None;
pool——顶点缓冲使用的内存池位置,可以指定以下几个内存池位置:
Default, Managed, SystemMemory, Scratch。
现在看看这个函数的构造函数:
如果代码是:
device.DrawPrimitives(PrimitiveType.LineStrip, 0,3);
执行结果是:
它把顶点绘制为一条折线。至少需要两个顶点。
如果代码为:
device.DrawPrimitives(PrimitiveType.PointList, 0,4);
执行结果是:
把数据作为一系列离散的点来绘制。
四、创建顶点缓冲
使用顶点缓冲可以大幅度提高工作效率,如果不使用顶点缓冲,当每次渲染场景里,都要分配新的顶点列表,并且所有的内容都要存储在系统内存里,如果使用顶点缓冲,则可以把顶点数据存放在显存中,这样会大幅度提高应用程序的性能;
在D3D中使用VertexBuffer()类来创建一个顶点缓冲,以下为其中一个构造函数:
public VertexBuffer( Type typeVertexType, int numVerts, Device device, Usage usage,VertexFormats vertexFormat, Pool pool);
其中各参数的含义如下:
device——创建顶点缓冲的device,创建的顶点缓冲只能被这个device使用;
usage——如何使用顶点缓冲。使用以下选项:
DoNotClip,Dynamic, Npatches, Points, PTPatches, SoftwareProcessing, WriteOnly;
以下代码示例为使用数组来读和写一个顶点缓冲区:
public struct PositionNormalTexVertex
{
public Vector3 Position;
public Vector3 Normal;
public float Tu0, Tv0;
public static readonly VertexFormats FVF = VertexFormats.Position | VertexFormats.Texture1;
}
public class Example
{
public void ArrayBasedReadWrite()
{
//创建一个顶点缓冲区
VertexBuffer vb = new VertexBuffer(typeof(PositionNormalTexVertex), 100, device, Usage.None, PositionNormalTex1Vertex.FVF, Pool.Managed);
//填充数据
PositionNormalTexVertex[] vbData = (PositionNormalTexVertex[]) vb.Lock(0, typeof(PositionNormalTexVertex), LockFlags.None, 50);
for(int i=0; i<50; i++)
{
//set your vertices to something...
Managed DirectX +C# 开发(入门篇)2 vbData[i].Position = new Vector3(2f,2f,2f);
vbData[i].Normal = new Vector3(1f,0f,0f);
vbData[i].Tu0 = i;
vbData[i].Tv0 = i;
}
vb.Unlock();
vbData = (PositionNormalTexVertex[]) vb.Lock(0, LockFlags.ReadOnly);
for(int i=0; i<100; i++)
{
//读取顶点数据
Console.WriteLine("Vertex " + i + "Tu: " + vbData[i].Tu0 + " , Tv: " + vbData[i].Tv0);
}
vb.Unlock();
vb.Dispose();
}
}
在本示例程序中,创建顶点缓冲是放在一个事件中,也就是说当创建程序时创建顶点缓冲,以后则不必再创建了。
程序执行结果如下:
五、坐标变换
现在生成的三角形,使用了一个叫做transformed坐标系统,这种坐标是显示器的屏幕所使用的坐标。但是不灵活,另一种是未经过变换的坐标系统。下面就来介绍这种坐标系统。
与屏幕坐标不同的是,可以把我们的空间想象成为一个无限大的三维笛卡尔直角坐标系,可以把绘图对象,比如人物、车等,放到任意位置,如果到时候想在屏幕上显示此人,可以把摄像机“对”着他就可以了,这和现实世界中的拍电影很类似。
为了介绍这个内容,首先把前面使用的顶点格式类型变过来,具体代码,可以看SDK示例三
VertexBuffer vb = (VertexBuffer)sender;
CustomVertex.PositionColored[] verts = (CustomVertex.PositionColored[])vb.Lock(0,0);
verts[0].X=-1.0f; verts[0].Y=-1.0f; verts[0].Z=0.0f; verts[0].Color = System.Drawing.Color.DarkGoldenrod.ToArgb();
verts[1].X=1.0f; verts[1].Y=-1.0f ;verts[1].Z=0.0f; verts[1].Color = System.Drawing.Color.MediumOrchid.ToArgb();
verts[2].X=0.0f; verts[2].Y=1.0f; verts[2].Z = 0.0f; verts[2].Color = System.Drawing.Color.Cornsilk.ToArgb();
vb.Unlock();
下面所要做的,需要给场景添加一个摄像机;然后让摄像机“照”着我们所创建的对象,当然,场景中还需要有灯光,不然,黑洞洞的,什么也没有;后面再介绍;
在device上通过两个不同的变换来控制摄像机。每一种变换都被定义为一个4×4的矩阵传递给DirectX3D,使用它,等于告诉摄像机场景如何投影到显示器。通常的做法是使用Matrix类的PerspectiveFovLH方法。
它使用左手坐标系创建一个正对场景的透视投影变换。
public static Matrix PerspectiveFovLH( float fieldOfViewY,float aspectRatio,float znearPlane,float zfarPlane);
此矩阵实际上是设计了一个梯形体,凡是在这里面的对象,都是可见的,在这个范围外面的,都将是不可见的。这个范围由由可视角度和前裁剪面(Near Plane)与后裁剪面(Far Plane)所决定,函数头里的nearPlane和farPlane两个参数,描绘了范围的边界:farPlane就是梯形体底面,而nearPlane则是横截面。fieldOfView参数描绘了梯形体的角度。aspectRatio类似于电视的高宽比,比如,宽银幕电视的高宽比是1.85。可以用可视区域的宽度来比上高度得出这个值。
下面还需要有一个函数来包含摄像机的信息,在D3D中这个函数就是LookAtLH(),先看它的构造函数:
public static Matrix LookAtLH(Matrix pOut, Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector);
构造函数中的参数的含义是:
摄像机的位置、摄像机观察点的位置以及一个被参考为“up”的方向。
有了这两个函数的帮忙,就可以在世界坐标系中显示三维对象了。
在示例三的程序中的代码是:
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 ) );
device.Transform.Projection = Matrix.PerspectiveFovLH( (float)Math.PI / 4, 1.0f, 1.0f, 100.0f );
另外,在程序中,为了更好的表现,加入了以下代码:
int iTime = Environment.TickCount % 1000;
float fAngle = iTime * (2.0f * (float)Math.PI) / 1000.0f;
device.Transform.World = Matrix.RotationY( fAngle );
Managed DirectX +C# 开发(入门篇)2此代码的作用是,让场景绕Y轴旋转,而旋转的角度值则为一个变化的值,这样就得到了一个旋转的三角形;
程序执行结果如下: