本文由哈利_蜘蛛侠原创,转载请注明出处!有问题请联系[email protected]
这一次我们继续来讲述Jim Adams老哥的RPG编程书籍第二版第二章的第4节:Getting Down to Drawing。这个超级长的节前两次讲了一多半内容,这一期我们要把它讲完。
再次将这一节的各小节的标题列在下面,以供大家参考:
1、Using Vertices (使用顶点)
2、Flexible Vertex Format (灵活顶点格式)
3、Using Vertex Buffers (使用顶点缓存)
4、Vertex Streams (顶点流)
5、Vertex Shaders (顶点着色器)
6、Transformations(变换)
7、The World Transformation (世界变换)
8、The View Transformation (视角变换)
9、The Projection Transformation (投影变换)
10、Materials and Colors (材质和颜色)
11、Clearing the Viewport (清除视口)
12、Beginning and Ending a Scene (开始和结束场景)
13、Rendering Polygons (渲染多边形)
14、Presenting the Scene (展示场景)
这一期要从Materials and Colors讲到最后的Presenting the Scene。
原文翻译:
===============================================================================
2.4.10 Materials and Colors (材质和颜色)
你已经看到了如何在顶点信息中声明颜色,但是当谈到多边形的时候,它们也有赋予它们的特定的颜色属性。你运用到一个多边形面上的颜色称为材质(materials)。在运用Direct3D来绘制多边形之前,你可以选择给材质进行赋值以供使用(如果你选择不使用材质,你可以使用顶点颜色,如果有顶点颜色的话)。
每一个材质都需要一些颜色值来对其进行描述。使用Direct3D,定义材质的颜色值储存在一个结构体中:
typedef struct_D3DMATERIAL9 { D3DCOLORVALUE Diffuse; // Diffuse color component D3DCOLORVALUE Ambient; // Ambient color component D3DCOLORVALUE Specular; // Specular color component D3DCOLORVALUE Emisive; // Emissive color component float Power; // Sharpness of specular highlights } D3DMATERIAL9;
在实际操作中,你只要处理一个颜色成分:Diffuse (漫反射)。你可以将Ambient 值设为与Diffuse 相同的值,并且你可以将Specular 设为0.0或1.0(等等!Specular不是一个3维向量吗?)(同时将Power
设为0.0)。我建议你尝试给这些颜色成分赋上不同的值,以便对每个颜色成分产生的效果有一个概念。
对于当前的目的来说,你将Diffuse 颜色运用到一个多边形面上;材质的颜色可以取代顶点结构中的漫反射颜色成分。如果你想要将一个材质的颜色运用到一个已经使用了带颜色的顶点的多边形面上的话,那么你会引起一个可以观察到的(并且通常是你不想要的)多边形颜色的改变。所以,最好是要么使用材质,要么使用顶点颜色,而不是二者同时使用。
在处理材质颜色成分的时候,你直接设定颜色成分,而非使用如D3DCOLOR_RGBA这样的宏。但是不需要担心——每个颜色成分都由它的首字母代替(r表示红色,g表示绿色,b表示蓝色,而a代表alpha 值),然后可以给它们赋上0.0到1.0之间的值。如果你想要创建一个材质来使用黄色,你可以如下建立材质结构体:
D3DMATERIAL9 d3dm; // Clear out thematerial structure ZeroMemory(&d3dm,sizeof(D3DMATERIAL9)); // Fill Diffuse andAmbient to Yellow color d3dm.Diffuse.r =d3dm.Ambient.r = 1.0f; // red d3dm.Diffuse.g =d3dm.Ambient.g = 1.0f; // green d3dm.Diffuse.b =d3dm.Ambient.b = 0.0f; // blue d3dm.Diffuse.a =d3dm.Ambient.a = 1.0f; // alpha
你如何建立材质结构体是你的选择,但是一旦该结构体建立起来后,你需要告诉Direct3D在渲染一个多边形之前使用该材质。这正是IDirect3DDevice9::SetMaterial 函数的工作,它只取一个指向你的材质结构体的指针作为参数:
IDirect3DDevice9::SetMaterial(CONSTD3DMATERIAL9 *pMaterial);
一旦被调用后,之后渲染的所有的多边形都会使用这个材质的设定。下面是设定之前定义的黄色材质的一个例子:
g_pD3DDevice->SetMaterial(&d3dm);
2.4.11 Clearing the Viewport (清理视口)
你需要将后台缓冲区打扫干净以准备进行绘制,这样就清除了也许存在于那里的图形。使用IDirect3DDevice9::Clear 函数的话,这就是一件简单的例行公事了:
HRESULTIDirect3DDevice9::Clear( DWORD Count, // 0 CONST D3DRECT *pRects, // NULL DWORD Flags, // D3DCLEAR_TARGET D3DCOLOR Color, // Color to clear to float Z, // 1.0f DWORD Stencil); // 0
现阶段唯一要担心的的参数是Color,它是你想要将后台缓冲区清理成的颜色。要使用的颜色值可以使用你生来就喜欢的、典型的D3DCOLOR_RGBA或D3DCOLOR_COLRVALUE宏来进行构造。假如说你想要将后台缓冲区清理成浅蓝色:
// g_pD3DDevice =pre-initialized device object if(FAILED(g_pD3DDevice->Clear(0,NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 192, 255), 1.0f, 0))) { // Error occurred }
注意
===============================================================================
示例中使用的D3DCLEAR_TARGET 标记告诉Direct3D 你想要清理当前的目标(屏幕或窗口)。还有一些有用的清理标记可供使用,其中的另一个你很快就会读到的。
===============================================================================
2.4.12 Beginningand Ending a Scene (开始和结束一个场景)
在你能够渲染任何东西之前,你必须告诉Direct3D 来自己做好准备。这就是IDirect3DDevice9::BeginScene 函数的目标(它不取参数):
HRESULTIDirect3DDevice9::BeginScene();
当你完成渲染场景之后,你需要告知Direct3D 来使用EndScene 函数:
HRESULTIDirect3DDevice9::EndScene();
你不需要将Clear函数的调用插入到BeginScene 和EndScene 之间;你可以在你调用BeginScene 函数之前调用Clear 函数。在开始场景和结束场景函数的调用之间唯一需要插入的东西是渲染多边形的函数。
2.4.13 RenderingPolygons (渲染多边形)
在漫长的煎熬之后,你要开始渲染多边形了!你的游戏引擎的典型框架会清理后台缓冲区、开始场景、设置要使用的材质、绘制多边形并结束场景。你已经看到了如何来做所有的这些事,除了绘制实际的多边形。
你使用下面的函数来绘制一个IDirect3DVertexBuffer9 对象(当然,是在调用设置顶点源和FVF着色器的函数之后):
HRESULTIDirect3DDevice9::DrawPrimitive( D3DPRIMITIVETYPE PrimitiveType, // Primitives to draw UINT StartVertex, // Vertex to start with (0) UINT PrimitiveCount); // # of primitives to draw
第一个参数PrimitiveType告诉Direct3D要绘制什么类型的多边形(它可以是表2.4中列出来的之一)。参数StartVertex 使得你决定从哪个顶点开始绘制(一般来说是0)。你将你想要绘制的图元(primitives)的总数赋给参数PrimitiveCount。
表2.4 DrawPrimitive的图元类型
类型 |
描述 |
D3DPT_POINTLISH |
将所有的顶点以像素进行绘制。 |
D3DPT_LINELIST |
绘制一列孤立的线条,这些线条每个使用两个顶点。 |
D3DPT_LINESTRIP |
绘制一列相互连接的线条。 |
D3DPT_TRIANGLELIST |
绘制一些每个使用三个顶点的多边形。 |
D3DPT_TRIANGLESTRIP |
绘制一个多边形带,第一个多边形使用三个顶点,而后面的每个多边形每个使用一个额外的顶点。 |
D3DPT_TRIANGLEFAN |
以扇形绘制一些多边形,且第一个顶点作为把手(所有的多边形都与之相连)。 |
你使用的图元类型取决于你如何将顶点数据填充进顶点缓存之中。如果你对每个多边形使用3个顶点,你使用D3DPT_TRIANGLELIST类型。如果你使用更加高效的类型,例如三角形带,那么就使用D3DPT_TRIANGLESTRIP类型。
现在唯一需要记住的事情就是你必须在渲染多边形之前使用IDirect3DDevice9::BeginScene 函数来开始场景;否则,DrawPrimitive 函数的调用是失败。
假如说你已经创建了一个包含6个顶点的顶点缓存,它构造了两个三角形并形成了一个正方形。渲染它们的步骤(当然还有BeginScene 和EndScene 函数,还要设定顶点源和FVF着色器)看起来如下所示:
// g_pD3DDevice =pre-initialized device object // pD3DVB =pre-initialized vertex buffer // sVertex =pre-constructed vertex structure // VertexFVF =pre-constructed FVF descriptor // Set the vertexstream and shader g_pD3DDevice->SetStreamSource(0,pD3DVB, 0, sizeof(sVertex)); g_pD3DDevice->SetFVF(VertexFVF); if(SUCCEEDED(g_pD3DDevice->BeginScene())){ // Render the polygons if(FAILED(g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2))) { // Error occurred } // End the scene g_pD3DDevice->EndScene(); }
2.4.14 Presentingthe Scene (显示场景)
在经过了漫长的煎熬之后(At long last)(怎么又是这句话?),你可以准备将后台缓冲区翻转到视口,然后向用户展示你的图形了,而你是通过下列函数来实现的:
HRESULTIDirect3DDevice9::Present( CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion);
你可以安全地将IDirect3DDevice9::Present 函数的所有参数都设为NULL,这告诉Direct3D 将整个显示屏进行更新(因为这个函数可以一次只显示一部分),如下列代码所示:
// g_pD3DDevice =pre-initialized device object if(FAILED(g_pD3DDevice->Present(NULL,NULL, NULL, NULL))) { // Error occurred }
就是这样了!为了创建更多的逼真的场景,你使用很多不同的顶点缓存来在你的世界中绘制各种各样的3-D物体。另外一种提高你的图形的真实性的方式是使用纹理映射。
===============================================================================
好啦,我们终于将这超级长的第2章第4节给搞定了!希望大家能够理解。如果不理解的话也没关系,可以去参考“龙书”第二版的第4章和第6章的内容,那里讲述得比较详细,也不难理解(但是会有一些显著的区别)。