6绘制 3D基本形状.docx
《6绘制 3D基本形状.docx》由会员分享,可在线阅读,更多相关《6绘制 3D基本形状.docx(41页珍藏版)》请在冰豆网上搜索。
6绘制3D基本形状
6.绘制3D基本形状
现在您已学到了如何以MicrosoftDirect3D立即模式来建立3D环境,整个迷宫只剩下最后一个关键片段:
建立一个3D对象并绘制出来。
在第五章中,您看到了Direct3D中的所有可用顶点。
您也看到了如何自行为顶点配置内存或自行使用顶点缓冲区去管理内存。
在本章中,您可以用这些顶点来建立3D基本形状(3Dprimitive)。
所谓3D基本形状是指由一群顶点组成的对象。
您所能建立的最基本形状是一个点串行(pointlist),它只是一些单一像素点的集合。
您也可以建立并绘制一个线串行(linelist),这是一个单像素宽线条的集合。
然而您所建立的通常是三角形。
Direct3D使用三角形(而非其它种多边形)来描述3D对象的各个面,因为三角形是共平面且是凸面形状(意谓他们比较容易快速绘制)。
Direct3D让您可以结合三角形来建立更复杂的多边形和网格。
如果运用大量的三角形时,您还可以达到逼近弧面(如球体)的效果。
BeginScene和EndScene方法
在进入绘制基本形状的细节之前,您应该要了解BeginScene和EndScene。
在Direct3D中,您可以用IDirect3DDevice7:
:
BeginScene方法来表示要开始绘制某个场景。
这个方法会告诉DirectX检查绘制数据和确定成像绘图页已经设定好了。
一旦使用该方法后,您可以开始用Direct3D方法来绘制场景中的对象所需的基本形状。
如果您在呼叫BeginScene前呼叫这些方法,Direct3D会传回D3DERR_SCENE_NOT_IN_SCENE。
一旦您的绘制工作告一段落。
您必须去呼叫IDirect3DDevice7:
:
EndScene来清除内部旗标(表示场景绘制进行中),更新快取数据,确定成像绘图页已完成。
您必须以BeginScene/EndScene组合把所有的对绘制方法的呼叫包起来。
如果BeginScene失败了,场景就不会开始,而且呼叫Endscene也会失败(因为一开始就没有启动场景)。
如果在呼叫BeginScene前某个绘图页没有回复,则它会传回DDERR_SURFACELOST。
如果绘图页在绘制过程中不见了,EndScene也会传回此错误值,而在呼叫绘制方法时也回传回错误。
注意一旦BeginScene成功之后,如果在场景绘制过程中传回了错误,您必须去呼叫EndScene来完成您的绘制过程。
记住一件重要的事,您必须先结束一个场景的绘制作业,才能再开始另外一个。
如果您试着要使用巢状BeginScene/EndScene组合,就会传回D3DERR_SCENE_IN_SCENE错误。
如果您呼叫了EndScene但没有呼叫BeginScene,也会有这种错误。
索引和非索引的基本形状
立即模式提供了二种将基本形状顶点分类的方式:
使用非索引基本形状和使用索引基本形状。
要建立一个非索引基本形状,您可以用有顺序的顶点序列填入数组中。
这里的顺序是指由数组中顶点顺序指示如何产生三角形。
第一个三角形是由数组中的前三个顶点所组成,第二个三角形是由接下来三个点所组成,依此类推。
这意谓着多个三角形不能共享顶点。
如果您有二个相连的三角形,您必须要定义同一个顶点很多次。
要建立一个索引基本形状,你可以用没有顺序的顶点序列填入数组中。
并且建立第二个数组,并且用一个有顺序的索引序列指向这个无顺序的数组中。
对索引基本形状而言,数组中的顶点顺序并不重要。
而是由索引数组中的索引顺序指示如何造出三角形。
第一个三角形是由索引数组中的前三个索引所参照的顶点所组成,第二个三角形是由接下来三个索引所参照的顶点所组成,依此类推。
这意谓着多个三角形可以共享顶点,只要让索引数组中的多个项目参照到同一个顶点即可。
本章稍后会谈到的三角条(strip)和扇,也是可以共享顶点,所以您应该依据3D对象的结构来选择使用索引或非索引基本形状。
大部分的3D模型分享多个顶点。
因此,您可以让多个三角形间(或线条)分享这些顶点来节省内存、频宽以及CPU时间。
当3D模型分享顶点时,索引顶点是很有用的。
然而要小心某些看起来可以共享,事实却不然的顶点。
立方体就是个典型的例子。
让构成立方体的12个三角形只须共享8个顶点,看起来很诱人。
但是如果您这样做,就会在这些点的法向量出问题。
每个三角形的面都有一个向量,称为表面法向量(facenormal),和平面垂直。
这个表面法向量指向远离三角形面的前方边缘,在Direct3D中这是唯一可见边。
因为法向量是依顶点而非面来定义,二个不同法向量的三角形就不能共享顶点。
即使他们可以,但是被共享的顶点只能有一个法向量,所以就无法产生您想得到的打光效果。
在立方体的情况中,事实上使用24个顶点会比较好,甚至比12个三角形所必须的36个顶点(不用索引时)还要好。
图6-1说明了这些法向量的组成。
图6-1 一个立方体表面的顶点法向量
DrawPrimitive方法
您可能开始觉得在绘制基本形状时有许多不同的情况要考虑。
您已经学到顶点有三种储存方式:
使用者数组、间插顶点和顶点缓冲区。
而且您已学到Direct3D可以绘制三种基本形状:
点、线和三角形。
线可以分成二种:
线串行(linelist)和线条块。
三角形可以区分成三种:
串行、条块和扇。
最后,基本形状可以是索引或非索引的。
如此一来,又增加了绘制基本形状时的许多不同方式!
IDirect3DDevice7接口的6种DrawPrimitive方法可以处理所有的情况。
表6-1说明了针对各种顶点型态和索引型态组合所适用的不同方法。
表6-1绘制基本形状的方法
基本形状的型态
一般的使用者顶点
间插的使用者顶点
顶点缓冲区
非索引
DrawPrimitive
DrawPrimitiveStrided
DrawPrimitiveVB
索引
DrawIndexedPrimitive
DrawIndexedPrimitiveStrided
DrawIndexedPrimitiveVB
让我们再详细看看这些方法
DrawPrimitive
IDirect3DDevice7:
:
DrawPrimitive方法会依您所提供作为任意几何基本形状类型的顶点数组来绘制。
以下是本方法的函式宣告:
HRESULTIDirect3DDevice7:
:
DrawPrimitive(
D3DPRIMITIVETYPEdptPrimitiveType,
DWORDdwVertexTypeDesc,
LPVOIDlpvVertices,
DWORDdwVertexCount,
DWORDdwFlags
);
参数
说明
dptPrimitiveType
这个指令所要绘制的基本形状型态。
这个基本形状型态必须是D3DPRIMITIVE列举型态的成员之一。
dwVertexTypeDesc
储存弹性顶点格式旗标的组合,用来定义这些基本形状集合会用到的顶点格式。
lpvVertices
指到在基本形状序列中用到的顶点数组的指针。
dwVertexCount
储存了数组中画出的顶点数目。
您可以指定的最大值是D3DMAXNUMVERTICES(65,535)。
dwFlags
将本参数设为0可在绘制基本形状时不用等待,如果设为D3DDP_WAIT,则使得方法会在回传前保持等待,直到多边形完成绘制。
预设情形下,这个方法会在将多边形传送到视讯卡后立刻回传。
可利用D3DDP_WAIT旗标值来除错。
程序不应在绘制前使用D3DDP_WAIT旗标来等待场景更新。
DrawPrimitiveStrided
IDirect3DDevice7:
:
DrawPrimitiveStrided方法是用间插顶点数组绘出多个几何形状。
您必须检查想绘制的顶点是否使用了所指定的格式。
因为Direct3D不会检查顶点大小和间插是否符合已设定的弹性顶点格式,您必须自行确认,否则就可能发生内存错误。
这里是方法的函式宣告:
HRESULTDrawPrimitiveStrided(
D3DPRIMITIVETYPEdptPrimitiveType,
DWORDdwVertexTypeDesc,
LPD3DDRAWPRIMITIVESTRIDEDDATAlpVertexArray,
DWORDdwVertexCount,
DWORDdwFlags
);
参数
说明
dptPrimitiveType
这个指令要绘制的基本形状型态。
这个参数必须是D3DPRIMITIVETYPE列举型态成员之一。
dwVertexTypeDesc
描述顶点格式的弹性顶点格式旗标的组合。
lpVertexArray
D3DDRAWPRIMITIVESTRIDEDDATA结构的地址,这个结构中包含了基本形状的顶点组件指针和内存间插值,这个参数的格式是由dwVertexTypeDesc中的旗标所设定。
dwVertexCount
lpVertexArray数组中的顶点数目。
可容许的最大顶点数是D3DMAXNUMVERTICES(0xFFFF)。
dwFlags
设为0可在绘制基本形状时不用等待,如果使用D3DDP_WAIT旗标,则使得方法会在回传前保持等待,直到多边形完成绘制,而不会在多边形传送到视讯卡后立刻回传。
(对场景撷取卡而言,当卡响应时方法会立刻回传。
)
本旗标值通常是来除错。
程序不应用D3DDP_WAIT旗标来等待场景更新后再继续。
DrawPrimitiveVB
IDirect3DDevice7:
:
DrawPrimitiveVB方法是用顶点缓冲区的顶点数组绘出多个几何基本形状。
这里是方法的函式宣告:
HRESULTDrawPrimitiveVB(
D3DPRIMITIVETYPEd3dptPrimitiveType,
LPDIRECT3DVERTEXBUFFER7lpd3dVertexBuffer,
DWORDdwStartVertex,
DWORDdwNumVertices,
DWORDdwFlags
);
参数
说明
pptPrimitiveType
这个指令要绘制的基本形状型态。
这个参数必须是D3DPRIMITIVETYPE列举型态成员之一。
lpd3dVertexBuffer
包含了顶点数组的顶点缓冲区的IDirect3DVertexBuffer7接口地址。
顶点可以是已转换或未转换,最佳化或未最佳化。
dwStartVertex
在基本形状中的第一个顶点的索引值。
最大可能启始索引是D3DMAXNUMVERTICES(0xFFFF)。
在除错过程中,如果指定一个超过此极值的启始索引值时,会造成方法失败且传回DDERR_INVALIDPARAMS。
dwNumVertices
绘制的顶点数。
可容许的最大顶点数是D3DMAXNUMVERTICES(0xFFFF)。
dwFlags
设为0可在绘制基本形状时不用等待,如果使用D3DDP_WAIT旗标,则使得方法会在回传前保持等待,直到多边形完成绘制,而不会在多边形传送到视讯卡后立刻回传。
(对场景撷取卡而言,当卡响应时方法会立刻回传。
)
本旗标值通常是来除错。
程序不应用D3DDP_WAIT旗标来等待场景更新后再继续。
DrawIndexedPrimitive
IDirect3DDevice7:
:
DrawIndexedPrimitive方法在绘制指定的几何基本形状时,会依据对顶点数组所作的索引而非直接使用某个顶点数组。
以下是本方法的函式宣告:
HRESULTIDirect3DDevice7:
:
DrawIndexedPrimitive(
D3DPRIMITIVETYPEd3dptPrimitiveType,
DWORDdwVertexTypeDesc,
LPVOIDlpvVertices,
DWORDdwVertexCount,
LPWORDlpwIndices,
DWORDdwIndexCount,
DWORDdwFlags
);
参数
说明
d3dptPrimitiveType
这个指令要绘制的基本形状型态。
这个参数必须是D3DPRIMITIVETYPE列举型态成员之一。
D3DPRIMITIVETYPE的D3DPT_POINTLIST成员则没有索引。
dwVertexTypeDesc
储存了弹性顶点格式旗标的组合,用来定义这些基本形状集合会用到的顶点格式。
lpvVertices
指到您在基本形状序列中要用到的顶点数组。
dwVertexCount
储存了lpvVertices参数指到数组中的顶点总数。
lpwIndices
指到某个WORD串行,在创造要绘制的几何形状时,这个串行可用作对顶点串行作索引。
dwIndexCount
定义用来创造几何形状的索引数目。
可容许的最大索引数是D3DMAXNUMVERTICES(0xFFFF)。
dwFlags
将本参数设为0可在绘制基本形状时不用等待,如果设为D3DDP_WAIT,则使得方法会在回传前保持等待,直到多边形完成绘制。
预设情形下,这个方法会在将多边形传送到视讯卡后立刻回传。
可利用D3DDP_WAIT旗标值来除错。
程序不应在绘制前使用D3DDP_WAIT旗标来等待场景更新。
DrawIndexedPrimitiveStrided
IDirect3DDevice7:
:
DrawIndexedPrimitiveStrided方法允许您依据对间插顶点数组所作的索引来绘制一个几何基本形状。
以下是本方法的函式宣告:
HRESULTDrawIndexedPrimitiveStrided(
D3DPRIMITIVETYPEd3dptPrimitiveType,
DWORDdwVertexTypeDesc,
LPD3DDRAWPRIMITIVESTRIDEDDATAlpVertexArray,
DWORDdwVertexCount,
LPWORDlpwIndices,
DWORDdwIndexCount,
DWORDdwFlags
);
参数
说明
d3dptPrimitiveType
这个指令要绘制的基本形状型态。
这个参数必须是D3DPRIMITIVETYPE列举型态成员之一。
D3DPRIMITIVETYPE的D3DPT_POINTLIST成员则没有索引。
dwVertexTypeDesc
描述基本形状的顶点格式的弹性顶点格式旗标组合。
lpVertexArray
D3DDRAWPRIMITIVESTRIDEDDATA结构的地址,这个结构中包含了基本形状的顶点组件的指针和内存间插,这个参数的格式是由dwVertexTypeDesc中的旗标所设定。
dwVertexCount
定义串行中的顶点数目。
这个参数的用法和Idirect3DDevice7:
:
DrawPrimitive方法中的dwVertexCount参数不同。
在那个方法中,dwVertexCount参数是指要画的顶点数,但这里则是代表了lpVertexArray参数指到的数组中的顶点总数。
当您呼叫IDirect-3DDevice7:
:
DrawIndexedPrimitiveStrided时,您会在dwIndexCount参数中指定要画的顶点数目。
lpwIndices
指到某个WORD串行,在创造要绘制的几何形状时,这个串行可用作对指定的顶点串行作索引。
dwIndexCount
定义用来创造几何形状的索引数目。
可容许的最大索引数是D3DMAXNUMVERTICES(0xFFFF)。
dwFlags
设为0可在绘制基本形状时不用等待,如果使用D3DDP_WAIT旗标,则使得方法会在回传前保持等待,直到多边形完成绘制,而不会在多边形传送到视讯卡后立刻回传。
(对场景撷取卡而言,当卡响应时方法会立刻回传。
)
本旗标值通常是来除错。
程序不应用D3DDP_WAIT旗标来等待场景更新后再继续。
DrawIndexedPrimitiveVB
IDirect3DDevice7:
:
DrawIndexedPrimitiveVB方法是依据对顶点缓冲区中顶点数组的索引来绘制一个几何基本形状。
以下是本方法的函式宣告:
HRESULTDrawIndexedPrimitiveVB(
D3DPRIMITIVETYPEd3dptPrimitiveType,
LPDIRECT3DVERTEXBUFFER7lpd3dVertexBuffer,
DWORDdwStartVertex,
DWORDdwNumVertices,
LPWORDlpwIndices,
DWORDdwIndexCount,
DWORDdwFlags
);
参数
说明
d3dptPrimitiveType
这个指令要绘制的基本形状型态。
这个参数必须是D3DPRIMITIVETYPE列举型态成员之一。
D3DPRIMITIVETYPE的D3DPT_POINTLIST成员则没有索引。
lpd3dVertexBuffer
包含顶点数组的顶点缓冲区的IDirect3DVertexBuffer7接口的地址。
dwStartVertex
顶点缓冲区中第一个要绘制的顶点索引。
dwNumVertices
顶点缓冲区中要绘制的顶点总数。
lpwIndices
某个WORD数组的地址。
这个数组是用来对顶点缓冲区中的顶点作索引。
数组中的值必须让顶点的索引结果落在范围dwNumVertices 0,-1 中。
dwIndexCount
数组lpwIndices中的索引数目。
可容许的最大索引数目是D3DMAXNUMVERTICES(0xFFFF)。
dwFlags
设为0可在绘制基本形状时不用等待,如果使用D3DDP_WAIT旗标,则使得方法会在回传前保持等待,直到多边形完成绘制,而不会在多边形传送到视讯卡后立刻回传。
(对场景撷取卡而言,当卡响应时方法会立刻回传。
)
本旗标值通常是来除错。
程序不应用D3DDP_WAIT旗标来等待场景更新后再继续。
基本形状的型态
DrawPrimitive方法使用了D3DPRIMITIVETYPE列举型态来列出这个方法支持的所有基本形状。
以下是型态的定义:
typedefenum_D3DPRIMITIVETYPE{
D3DPT_POINTLIST=1,
D3DPT_LINELIST=2,
D3DPT_LINESTRIP=3,
D3DPT_TRIANGLELIST=4,
D3DPT_TRIANGLESTRIP=5,
D3DPT_TRIANGLEFAN=6
D3DPT_FORCE_DWORD=0x7fffffff,
}D3DPRIMITIVETYPE;
这里是D3DPRIMITIVETYPE列举型态的成员:
∙ D3DPT_POINTLIST 让DrawPrimitive方法绘制顶点成为一些独立点的集合。
∙ D3DPT_LINELIST 让DrawPrimitive方法绘制顶点成为独立直线段(isolatedstraight-linesegment)的串行。
您必须设定大于或等于2的偶数个顶点。
∙ D3DPT_LINESTRIP 让DrawPrimitive方法绘制顶点成为单一的polyline。
您必须设定至少二个顶点。
∙ D3DPT_TRIANGLELIST 让DrawPrimitive方法绘制顶点成为连续的独立三角形。
每三个顶点定义一个单一的三角形。
您必须设定至少三个顶点并确定顶点数目是3的倍数。
winding-order绘制状态定义了背面排除(backfaceculling,或称backfaceremoval)的运作方式。
(我们会在本章后面讨论背面排除和winding-order绘制状态)
∙ D3DPT_TRIANGLESTRIP 让DrawPrimitive方法绘制顶点成为一个三角形的条。
您必须提供至少三个顶点。
DrawPrimitive方法会不依照顺序拿出偶数个三角形的顶点,以确保画三角形是依照顺时针方向开始。
(要知道更多信息,请看本章后面的 <排除状态> )
∙ D3DPT_TRIANGLEFAN 让DrawPrimitive方法绘制顶点成为一个三角形扇。
您必须定义至少三个顶点。
∙ D3DPT_FORCE_DWORD 强制列举型态为32位型态。
下一段谈到了这些基本形状的型态,您可以用来建立您的程序中的3D内容。
点串行
您可以用第一个基本形状型态-点串行(pointlist),来定义一群绘成独立点的顶点。
您可以在3D场景中用点串行来表示如虚线的对象。
要建立一个点串行,您需要填入一个顶点数组。
以下的程序范例说明了如何去执行这个作业。
虽然我是用一个简单的6元素串行,如果您想的话,您也可以用点串行来建立一个星场;当然串行中要有很多很多的点。
我比较习惯用环绕着3D世界贴图方式的球体来创造星场,因为这样可以用贴图动画来创造出多种效果。
constDWORDTOTAL_VERTICES=6;
D3DVERTEXlpVerticesTOTAL_VERTICES;
.
.
.
D3DVECTORv1(-1,4,0);
D3DVECTORv2(2,-1,0);
D3DVECTORv3(1,3,0);
D3DVECTORv4(-3,-2,0);
D3DVECTORv5(3,2,0);
D3DVECTORv6(2,1,0);
D3DVECTORvNormal(0,0,-1);
lpVertices[0]==D3DVERTEX(v1,vNormal,0,0);
lpVertices[1]==D3DVERTEX(v2,vNormal,0,0);
lpVertices[2]==D3DVERTEX(v3,vNormal,0,0);
lpVertices[3]==D3DVERTEX(v4,vNormal,0,0);
lpVertices[4]==D3DVERTEX(v5,vNormal,0,0);
lpVertices[5]==D3DVERTEX(v6,vNormal,0,0);
一旦您定义了点串行,您可以用之前说过的IDirect3DDevice7:
:
DrawPrimitive方法来绘制出。
以下是绘制点串行的程序代码。
本章前面学过,任何对IDirect3DDevice7:
:
DrawPrimitive的呼叫都必须落在呼叫IDirect3DDevice7:
:
BeginScene和IDirect3DDevice7:
:
EndScene中间。
if(FAILED(lpDirect3DDevice7->BeginScene()))
{
//如果有错误时,在此处理。
}
.
.
.
if(FAILED(lpDirect3DDevice7->DrawPrimitive(D3DPT_POINTLIST,
D3DFVF_VERTEX,lpVertices,TOTAL_VERTICES,0)))
{
//如果有错误时,在此处理。
}
.
.