Vertices

[Previous] [Next]

All primitives that DirectX can render are made from vertices. In geometry, a vertex is a point in space that defines a corner of a polygon. A Direct3D vertex holds the coordinates of its position and can also store information such as a normal vector, texture coordinates, and color information. Vertices get transformed by Direct3D from a user-specified format to a format that is ready to be rasterized. DirectX 6 introduced the flexible vertex format that lets us define vertices in several new ways. Before this, only the following three predefined types of vertices were available:

  • D3DVERTEX (untransformed, unlit vertices) If you choose not to light or transform your vertices before passing them to Direct3D, use this vertex type. You need to declare the lighting parameters and transformation matrices, but Direct3D computes the lighting and transformation for you.
  • D3DLVERTEX (untransformed, lit vertices) If you choose to light but not transform your vertices before passing them to Direct3D, you should use this vertex type. Also use these vertices if you want to compute your own custom lighting effects.
  • D3DTLVERTEX (transformed, lit vertices) If you choose to light and transform your vertices before passing them to Direct3D, you should use this vertex type. The T&L pipeline will skip transforming and lighting the vertices, but it will clip them if necessary. You can tell Direct3D that you intend to do your own clipping by using the D3DDP_DONOTCLIP flag when you call a rendering method. You should use the D3DDP_DONOTCLIP option with this type of vertex because if Direct3D is told to clip the transformed and lit vertices, it will have to back-transform them to projection space for clipping and then transform them back to screen space. This additional transformation causes additional overhead that you should attempt to avoid so that your application will run efficiently.

Flexible Vertex Formats

Although the original types are still very useful, the flexible vertex formats are even better. In the flexible vertex format, only the necessary vertex components are used, saving a fair amount of memory bandwidth and rendering time. Vertices are defined with a combination of flexible vertex format flags. Each rendering method available through the IDirect3DDevice7 interface takes a combination of these flags to describe the format of the vertices being passed to Direct3D. These flags indicate which vertex components (position, normal, colors, and the number of texture coordinates) you want to use—and thus are currently in memory—and which portions of the rendering pipeline you want applied to them.

When using the flexible vertex format, you must format all the vertices in the following order (although you'll never use all of these at once):

  1. Position (untransformed or transformed x, y, z)—(float) x coordinate, y coordinate, and z coordinate
  2. RHW (only transformed vertices)—(float) rhw (the reciprocal-of-homogeneous-w)
  3. Blending weight values—1-5 floats
  4. Vertex normal (only untransformed vertices)—(float) normal x, normal y, normal z
  5. Diffuse color—(DWORD) diffuse RGBA
  6. Specular color—(DWORD) specular RGBA
  7. Texture coordinate sets 1-8—(float) u coordinate, v coordinate

To request the untransformed and unlit vertex type, use the D3DFVF_XYZ and D3DFVF_NORMAL flags together in the vertex description passed to the rendering methods. This vertex type requests that Direct3D perform all transformation and lighting operations using its internal algorithms, unless you pass the D3DDP_DONOTLIGHT flag to the rendering methods, which asks Direct3D to disable the lighting engine for the primitives being rendered.

If you use just the D3DFVF_XYZ flag, the vertices are considered by Direct3D to be untransformed but already lit. Direct3D doesn't perform any lighting calculations on untransformed and lit vertices, but it still transforms them using the previously set world, view, and projection matrices.

The D3DFVF_XYZRHW flag indicates that the vertices are already transformed and lit. Direct3D doesn't transform vertices with the world, view, or projection matrix, and it doesn't do any lighting calculations because this flag indicates that these operations have already been performed.

With DirectX 7, you can specify texture coordinates in different formats. This capability allows textures to be addressed using from one to three texture coordinates. (You'd use three if you were using 2D-projected texture coordinates.) The D3DFVF_TEXCOORDSIZEn series of macros create bit patterns that define the texture coordinate formats that our vertex format will use.

Left-Handed and Right-Handed Coordinate Systems

Direct3D uses a left-handed coordinate system. In both left-handed and right-handed coordinate systems (the two most popular coordinate systems in 3D programming), the positive x-axis points to the right and the positive y-axis points up. The z-axis, however, points in a different direction in each system. You can remember the direction in which the positive z-axis points by turning your palm up and pointing the fingers of your hand in the positive x direction and curling them in the positive y direction. The direction your thumb points, which in the left-handed coordinate system is away from you, is the direction the positive z-axis points for the coordinate system. Figure 5-7 illustrates this concept.

click to view at full size.

Figure 5-7 The left-handed and right-handed coordinate systems

To port an application from a right-handed to a left-handed coordinate system, change the 3D data as follows:

  1. Flip the order of the vertices of each triangle in an object so that they are transversed clockwise from the front. For example, if the vertices are defined as V0, V1, and V2 in the original triangle, you should switch them and pass them as V0, V2, and V1.
  2. Set up a view matrix to scale the world space by -1 in the z direction by just flipping the sign of the third row in the matrix (the _31, _32, _33, and _34 members of the view matrix's D3DMATRIX structure).

Strided Vertex Format

Direct3D provides a vertex type called the strided vertex format that can be used to represent untransformed vertices. Unlike a regular vertex, which consists of a structure that contains all the components of a vertex, a strided vertex contains pointers to those components. This gives you the freedom to organize the vertex components in different ways. Without strided vertices, all the information for one vertex is provided, then all the information for the second vertex, and so on. With strided vertices, you can remove some or all of this interleaving of information. As an example, you could have the position information for all the vertices in a contiguous array, followed by all the normal information, followed by all the texture coordinates.

You're not restricted to any specific interleaving scheme, so any approach that sets the data pointers and their strides correctly is acceptable. Strided vertices are a fairly advanced feature that you can use to ultra-optimize your program (for example, increasing the CPU cache performance). You'll probably find that you don't need to use them.

The D3DDRAWPRIMITIVESTRIDEDDATA structure used with the IDirect3DDevice7::DrawPrimitiveStrided and IDirect3DDevice7::DrawIndexedPrimitiveStrided methods is defined as follows:

 typedef struct D3DDRAWPRIMITIVESTRIDEDDATA  {     D3DDP_PTRSTRIDE position;     D3DDP_PTRSTRIDE normal;     D3DDP_PTRSTRIDE diffuse;     D3DDP_PTRSTRIDE specular;     D3DDP_PTRSTRIDE textureCoords[D3DDP_MAXTEXCOORD]; } D3DDRAWPRIMITIVESTRIDEDDATA , *LPD3DDRAWPRIMITIVESTRIDEDDATA; 

This structure contains the following members:

  • position and normal Hold D3DDP_PTRSTRIDE structures that point to an array of position and normal vectors for a collection of vertices. Each of these vectors is a three-element array of float values.
  • diffuse and specular Hold D3DDP_PTRSTRIDE structures that point to an array with diffuse and specular color information for a collection of vertices. Each element of the array is a 32-bit RGBA value, with 8 bits allocated for each color component (R, G, B, and A).
  • textureCoords Holds an eight-element array of D3DDP_PTRSTRIDE structures. Each element in the array is, in turn, an array of texture coordinates for the collection of vertices. You can find which array of texture coordinates you need to use for a given texture stage by calling the IDirect3DDevice3::SetTextureStageState method with the D3DTSS_TEXCOORDINDEX value.

The D3DDRAWPRIMITIVESTRIDEDDATA structure holds 12 D3DDP_PTRSTRIDE structures, one for each position, normal, diffuse color, and specular color member, plus four structures for the texture coordinates member. The D3DDP_PTRSTRIDE structure is defined as shown here:

 typedef struct _D3DDP_PTRSTRIDE {     LPVOID lpvData;     DWORD  dwStride; } D3DDP_PTRSTRIDE; 

This structure contains the following members:

  • lpvData The address of an array of data.
  • dwStride The memory stride between elements in the array.

Each of the D3DDP_PTRSTRIDE structures in the D3DDRAWPRIMITIVESTRIDEDDATA structure holds a pointer to an array of data and to the stride (the distance between elements in the array) of that array. You can set the dwStride member of the D3DDP_PTRSTRIDE structure to the memory stride (in bytes) from one entry in the array to the next. You can use the 12 structures you define to arrange the vertex components however you want. For example, suppose you want to use separate arrays for each vertex component, such as a set of arrays holding the position (float), normal (float), diffuse (RGBA value), specular (RGBA value), and texture (float) information. In this case, an untransformed position or a vertex normal has a stride of three float variables: (x, y, z) for position and (nx, ny, nz) for vertex normal. Furthermore, diffuse and specular color have a stride of one DWORD (RGBA), and a texture coordinate has a stride of two float values (u, v).

Vertex Buffers

It is possible to have your program allocate memory for an array of vertices and pass a pointer to that array to a Direct3D primitive-drawing function. The preferred approach, however, is to let Direct3D manage the memory that holds the vertex array in an object called a vertex buffer. Using vertex buffers has several advantages over managing the vertex memory yourself. Vertex buffers can be placed in video memory rather than system memory if that will improve performance (as it will when transformation and lighting takes place in hardware). Vertex buffers also let the programmer separate the T&L stage from the rasterization stage, by calling IDirect3DVertexBuffer7::ProcessVertices to transform and light the vertices but not rasterize them yet. This is useful when doing multipass rendering, in which the same object is rendered multiple times with different textures or other properties. Without vertex buffers, your program couldn't specify that vertices be transformed and lit once but rasterized multiple times.

Here's the function declaration for this method:

 HRESULT IDirect3DVertexBuffer7::ProcessVertices(     DWORD dwVertexOp,     DWORD dwDestIndex,     DWORD dwCount,     LPDIRECT3DVERTEXBUFFER7 lpSrcBuffer,     DWORD dwSrcIndex,     LPDIRECT3DDEVICE7 lpD3DDevice,     DWORD dwFlags ); 

ParameterDescription
dwVertexOpCan hold a combination of the following flags to describe how the method will process the vertices as they are transferred from the source buffer:

D3DVOP_CLIP Used with vertex buffers containing clipping information; vertices are transformed and clipped if they are outside the viewing frustum.

D3DVOP_EXTENTS Updates the extents of the screen rectangle when the vertices are rendered after they are transformed. The extents returned by IDirect3DDevice7::GetClipStatus won't have been updated with the new vertex information when they are rendered.

D3DVOP_LIGHT Indicates that you want to light the vertices.

D3DVOP_TRANSFORM Requests transformation of the vertices using the world, view, and projection matrices. This flag always needs to be set.

dwDestIndexThe index into this destination vertex buffer where the vertices are placed after processing.
dwCountThe number of vertices in the source buffer to process.
lpSrcBufferThe address of the IDirect3DVertexBuffer7 interface for the source vertex buffer.
dwSrcIndexThe index of the first vertex in the source vertex buffer to be processed.
lpD3DDeviceThe address of the IDirect3DDevice7 interface for the device that will be used to transform the vertices.
dwFlagsProcessing options. Set this parameter to 0 for default processing. Set it to D3DPV_DONOTCOPYDATA to prevent the system from copying vertex data not affected by the current vertex operation into the destination buffer.



Inside Direct3D
Inside Direct3D (Dv-Mps Inside)
ISBN: 0735606137
EAN: 2147483647
Year: 1999
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net