六.顶点格式

  下面我们来讨论有关声明顶点和顶点格式的有关内容:

注:在DirectX 6.0之前,程序使用三种顶点类型——D3DVERTEX、D3DLVERTEX和D3DTLVERTEX——中的一种时,需要考虑正在使用几何管道中的哪一部分。随着DirectX 6.0中更加灵活的顶点格式的出现,使得我们有了比以前更多的声明方式,但是仍然要使用预先定义的结构来描述不进行变换和灯光处理的顶点、进行变换但进行灯光处理的顶点和进行变换和灯光处理的顶点。

 

1. 关于顶点格式

  Direct3D立即模式可以以不同的方式来定义模型顶点。并且支持可塑(flexible)顶点格式,这就是的程序可以只使用需要的顶点成分,而去掉那些不用的成分。这样,程序就可以减少内存的使用和渲染时的处理带宽。

  通过对可塑(flexible)顶点格式标志的组合,我们可以描述如何对顶点进行安排。IDirect3DDevice3的每种渲染方法都接收这些标志的组合,并且用它们来决定如何对图元进行渲染。这些标志会通知系统在程序中使用哪些顶点成分——位置、法向量、颜色和纹理坐标的数量,并间接的决定使用渲染管道的哪些部分。另外,某种特殊的顶点格式标志的出现或缺席,也会通知系统哪些顶点成分在内存中,以及你可能忽略了哪些成分。

注:如果程序中使用了IDirect3DDevice3::DrawPrimitiveStrided或IDirect3DDevice3::DrawIndexedPrimitiveStrided方法,那么,表现可能会有所不同。详细内容见“跨距顶点格式”。

  在系统决定如何来安排顶点时,还有一个需要就是数据出现的顺序。下图中向我们展示了所有可能的顶点成分在内存中所需的顺序,以及相应的数据类型:

pic70.gif (21548 bytes)

  没有程序会使用每一个单独的成分——RHW(齐次W的倒数,reciprocal homogenous W)和顶点法线域(vertex normal fields)除外,大多数程序一般也不会使用纹理坐标系的所有8个设置,这里的使用是很灵活的。一些标志与其它标志一起使用时,会有一些限制。这也是容易理解的。例如,D3DFVF_XYZD3DFVF_XYZRHW标志不能一起使用,因为一起使用它们时,就会以untransformedtransformed两种形式共同来描述顶点位置。

 

2. 不进行变换和灯光处理的顶点

  在描述顶点时使用D3DFVF_XYZD3DFVF_NORMAL标志,就表示渲染方法将使用untransformedunlit顶点类型。在使用这类顶点时,需要利用Direct3D内部的所有变换和光线操作。(如果需要的话,可以将D3DDP_DONOTLIGHT传递给渲染方法,使Direct3D的光线引擎无效。)

  大多数的程序都使用这种顶点类型,这样就可以不必使用程序自己的变换和光线引擎了。但是,由于要求系统来执行运算,所以要为每个顶点提供必要的信息:

  除了这些要求之外,还需要灵活的来使用(或忽略)其它的顶点成分。例如,在DirectX 6.0中可以对未变换的顶点使用漫射或镜面颜色,而这在以前的版本中是不可能的。这些颜色成分可以对每个顶点的材质颜色产生影响,从而产生出一种经过明暗处理后的效果,这样的方法要比只使用材质颜色的光线运算更加精细和灵活。Untransformedunlit顶点也可以包括上述的8种纹理坐标设置。

  程序仍然可以使用D3DVERTEX结构。实际上,d3dtypes.h头文件中定义了一个简便的宏来确定这种顶点格式:

#define D3DFVF_VERTEX ( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 )

  如果D3DVERTEX结构不符合程序的需要,那么你可以自己来进行定义。但要记住程序需要哪些顶点成分,并确定它们出现的顺序。下面的代码声明了一个有效的顶点格式结构,包括了位置、顶点法向量、漫射颜色和两种纹理坐标设置:


//
// The vertex format description for this vertex
// would be: (D3DFVF_XYZ | D3DFVF_NORMAL |
// D3DFVF_DIFFUSE | D3DFVF_TEX2)
//

typedef struct _UNLITVERTEX {
     float x, y, z; // position
     float nx, ny, nz; // normal
     DWORD dwDiffuseRGBA; // diffuse color
     float tu1, // texture coordinates
       tv1;
     float tu2,tv2;
} UNLITVERTEX, *LPUNLITVERTEX;

  上面描述的顶点是D3DFVF_XYZD3DFVF_NORMALD3DFVF_DIFFUSED3DFVF_TEX2可塑(flexible)顶点格式标志的组合。渲染方法,如IDirect3DDevice3::DrawPrimitive,将一个顶点数组地址作为一个void指针,所以在调用渲染方法时,要将顶点数组的地址指针分配给LPVOID数据类型。

 

3. 不进行变换但进行灯光处理的顶点

  如果在描述顶点格式时包含了D3DFVF_XYZ标志,而没有包含D3DFVF_NORMAL标志,那么就表示程序中的顶点没有经过变换,但是已经经过了光线处理。

  使用untransformedlit顶点,程序要求Direct3D不对顶点执行任何的光线操作,但是仍然要对顶点进行世界、观察和透视变换。由于系统不执行光线计算,因此也就不需要顶点法向量。系统在每个顶点使用漫射和镜面成分来进行明暗处理。这些颜色可以是任意的,也可以使用程序自己的光线运算公式来得到。如果没有包含漫射或镜面成分,系统将使用默认颜色。默认的漫射颜色是0xFFFFFFFF,镜面颜色是0x00000000

  和其它顶点类型一样,除了要包含位置信息和一些颜色信息以外,你可以在unlit顶点格式中自由的选择使用纹理坐标设置。

  程序也可以使用D3DLVERTEX结构。d3dtypes.h头文件中定义了一个下面的辅助宏来描述D3DLVERTEX结构的格式:

#define D3DFVF_LVERTEX ( D3DFVF_XYZ | D3DFVF_RESERVED1 | D3DFVF_DIFFUSE | \ D3DFVF_SPECULAR | D3DFVF_TEX1 )

  注意,这个辅助宏中包含了D3DFVF_RESERVED1标志,它向系统指明你正在使用D3DLVERTEX结构,其中包含了dwReserved成员。在使用D3DLVERTEX时,这样做是需要的,因为顶点格式并不总是包含保留于;D3DFVF_RESERVED1标志通知系统在顶点的位置成分与漫射颜色成分之间还有一个没有使用的DWORD

  如果D3DLVERTEX结构没有包含程序所需的所有域,你还可以另外定义一个结构体。下面的代码声明了一个untransformedlit顶点,并使用了漫射和镜面顶点颜色和三个纹理坐标设置:


//
// The vertex format description for this vertex
// would be: (D3DFVF_XYZ | D3DFVF_DIFFUSE |
// D3DFVF_SPECULAR | D3DFVF_TEX3)
//

typedef struct _LITVERTEX {
      float x, y, z; // position
      DWORD dwDiffuseRGBA; // diffuse color
      DWORD dwSpecularRGBA; // specular color
      float tu1, // texture coordinates
        tv1;
      float tu2,tv2;
      float tu3,tv3;
} LITVERTEX, *LPLITVERTEX;

  上面结构中描述的顶点是D3DFVF_XYZD3DFVF_DIFFUSED3DFVF_SPECULARD3DFVF_TEX3可塑(flexible)顶点格式标志的组合。渲染方法,如IDirect3DDevice3::DrawPrimitive,将一个顶点数组地址作为一个void指针,所以在调用渲染方法时,要将顶点数组的地址指针分配给LPVOID数据类型。

 

4. 经过变换和灯光处理的顶点

  在描述顶点格式时使用D3DFVF_XYZRHW标志,就表示程序将使用transformedlit顶点。对于顶点,Direct3D不再执行世界、观察和透视变换,也不再进行光线运算;它会认为顶点已经经过了这些处理(在立即模式输入已有的3-D程序时,场使用这种顶点。);并直接将顶点传递给驱动器进行光栅操作。

  如果出现D3DFVF_XYZRHW标志,那么与untransformed顶点和光线相关的顶点格式标志(D3DFVF_XYZD3DFVF_NORMAL)将不再被允许。

  使用这种顶点时,系统需要顶点的位置是已经经过变换了的。也就是说,xy的值必须在屏幕坐标系中,z必须是z-buffer中的像素的深度值。Z值的范围可以从0.01.0,离观察者最近的地方为0.0,观察范围内最远可见的地方为1.0。紧跟着位置信息,transformed and lit顶点必须要包含一个RHW值。RHW是投影空间中顶点所在的齐次点(homogeneous point(x,y,z,w)W坐标的倒数(reciprocal)。(它通常是沿z-轴从观察点到顶点的距离。)

  除了需要位置和RHW值之外,这种顶点与untransformed and lit顶点比较相似。

  程序仍然可以使用D3DTLVERTEX结构,d3dtypes.h头文件中定义了如下的辅助宏:

#define D3DFVF_TLVERTEX ( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | \ D3DFVF_TEX1 )

  有时,D3DTLVERTEX中可能没有包含你所需要的域。这时,可以另外定义一个结构体。下面的代码声明了一个transformedlit顶点,它使用漫射和镜面顶点颜色和一种纹理坐标设置:


//
// The vertex format description for this vertex
// would be: (D3DFVF_XYZRHW | D3DFVF_DIFFUSE |
// D3DFVF_SPECULAR | D3DFVF_TEX1)
//
typedef struct _TRANSLITVERTEX {
       float x, y;          // screen position
       float z;           // Z-buffer depth
       float rhw;          // reciprocal homogeneous W
       DWORD dwDiffuseRGBA;   // diffuse color
       DWORD dwSpecularRGBA;  // specular color
       float tu1,tv1;        // texture coordinates
} TRANSLITVERTEX, *LPTRANSLITVERTEX;

  上面的顶点描述是D3DFVF_XYZRHWD3DFVF_DIFFUSED3DFVF_SPECULARD3DFVF_TEX1可塑(flexible)顶点格式标志的组合。渲染方法,如IDirect3DDevice3::DrawPrimitive,将一个顶点数组地址作为一个void指针,所以在调用渲染方法时,要将顶点数组的地址指针分配给LPVOID数据类型。

 

5. 跨距顶点格式

  跨距顶点个是可以用来描绘litunlituntransformed顶点,它使用IDirect3DDevice3::DrawPrimitiveStridedIDirect3DDevice3::DrawIndexedPrimitiveStrided方法。对于transformed顶点不能使用跨距顶点格式。与其它“一般的”顶点(它包含的是所有需要的顶点成分)相比,一个跨距顶点结构中包含的是指向顶点成分的指针而不是顶点成分本身。

  这种方式是通过D3DDRAWPRIMITIVESTRIDEDDATA结构来完成的,DrawPrimitiveStridedDrawIndexedPrimitiveStrided方法都支持这种结构。在描述跨距顶点时,和以使用与非跨距顶点相同的可塑(flexible)顶点格式标志的组合。但是,和非跨距顶点不同的是,这里使用的标志并不表示给定的域(a given field)会出现在内存中(D3DDRAWPRIMITIVESTRIDEDDATA中包含了它们),它们只表示程序要使用哪些结构成员。对于这些标志的一些限制,跨距顶点与非跨距顶点是一样的,详细内容见“可塑(flexible)顶点格式标志”。

  D3DDRAWPRIMITIVESTRIDEDDATA结构包含了12D3DDP_PTRSTRIDE结构,分别用于顶点的位置、法向量、漫射颜色、镜面颜色和纹理坐标设置。每一个D3DDP_PTRSTRIDE结构都包含了一个指向数据数组的指针,和这些数组的跨距(stride)。这12个结构向程序间接提供了组织顶点成分的功能。我们可以向下图中那样,为每个顶点成分提供不同的数组:

pic71.gif (19716 bytes)

  相应的D3DDP_PTRSTRIDE结构的lpvData成员包含着一个缓冲区的地址,在这个缓冲器中是顶点成分数组。数组的每个元素都代表一个顶点的一个成分,它可以是一些浮点数(如位置、法向量和顶点坐标)或一个RGBA值(漫射和镜面颜色)。对于所有顶点,都由一个访问每个数组的入口。D3DDP_PTRSTRIDEdwStride成员用来设置从一个数组入口到另一个数组入口间的内存跨距(memory stride),它以字节形式来表示。下面的表格描述了不同的顶点成分及相应的跨距:

Component

Stride

untransformed position

3 floats (x,y,z)

vertex normal

3 floats (nx,ny,nz)

diffuse color

1 DWORD (RGBA)

specular color

1 DWORD (RGBA)

texture coordinate set

2 floats (u,v)

  有些程序人员可能在一个交叉存取数组(interleaved array)中选择包含一些或所有的顶点成分。使用跨距顶点格式可以使这项工作变得非常轻松。例如,当程序对顶点位置和法向量成分进行交叉存取时,下图中就显示了相应的内存规划和D3DDP_PTRSTRIDE结构的设置:

pic72.gif (8281 bytes)

  这样,D3DDP_PTRSTRIDE结构的lpvData成员就指向了同一缓冲区中的两个位置,而跨距就是两个成分的组合宽度。当然,我们并没有限制你非要使用特别的交叉存取配置。只要正确的设置数据指针和它们的跨距,任何交叉存取配置都可以正常运行。

 

上一页 | 目录 | 下一页