DirectX 9.0c Game Development notes of RPG programming self-learning log eight--drawing with DirectX graphics (drawing with DirectX graphic) (4th) (A)

Source: Internet
Author: User

This article by Harry _ Spider-Man original, reproduced please indicate the source! If you have any questions, please contact [email protected]

This time we continue to talk about Jim Adams old brother's RPG Programming Book Second Edition, chapter 4th, section Two: Getting down to Drawing. This section can be said to be super long, so we will be divided into 3 times!

As the content of this section is so much, the headings of the sections in this section are listed below for your reference:

1. Using Vertices ( with vertices )

2. Flexible Vertex format ( flexible vertex format )

3. Using Vertex buffers ( with vertex caching )

4. Vertex Streams ( vertex stream )

5. Vertex Shaders ( vertex shader )

6. Transformations ( transform )

7. The World Transformation ( Global Transformation )

8. The View transformation ( Perspective transform )

9. The Projection transformation ( projection transform )

10. materials and Colors ( materials and Colors )

11. clearing the Viewport ( Clear viewport )

12. Beginning and ending a scene ( start and end scenes )

13. Rendering Polygons ( render polygon )

14. presenting the scene ( show scenes )

This issue is to be referred to vertex Shaders from using vertices.

Original translation:


2.4 Getting down to Drawing ( start drawing )

The basic part speaks enough; it's time to see how Direct3D is drawing. In this section, I'll cover the basics of using vertices and polygons to draw graphics. You'll learn the various ways Direct3D use vertices to draw polygons, how to paint them, and ultimately show them to the user. The so-called details determine success or failure, so we should study the methods of dealing with vertices, and then continue to move forward from here.

2.4.1 Using Vertices ( use vertex )

Direct3D gives you a number of different ways to define a vertex. For example, if you are using 2-d graphics, you can set coordinates in the 2-d screen coordinates (transformed coordinates).

On the other hand, if you are using local or world space coordinates, you can set the coordinates in the z-coordinate (not transformed coordinates). So how do you use color and texture? You can choose to include this information in your vertex definition.

So how do you keep track of all this information and keep Direct3D until you're doing it? See flexible vertex format.

2.4.2 Flexible Vertex format ( flexible vertex formats )

flexible vertex formats (flexible vertex format, abbreviated FVF) are used to construct custom vertex data for use in your application. With FVF, you have to decide what information you want to use for your vertices-such as the z-coordinate, 2-d coordinates, colors, and so on.

You use a standard structure to create FVF, and in this structure you only add the ingredients you want. There are, of course, some limitations, such as that you must enumerate these ingredients in a particular order, and that some components do not conflict with other components (for example, using both 2-d and z-coordinates). Once this struct is complete, you create a FVF descriptor (FVF descriptor), which is a combination of a series of tags that describe your vertex format.

The following code block contains a vertex structure that uses a variety of variables that are allowed in FVF (or at least all of the variables I use in this book). The order in which the variables are enumerated in the struct is strictly consistent with the order in which they appear in your own structure; If you truncate any variables, keep the remaining order:

typedef struct {  FLOAT            x, y, z, RHW;       2-d coordinates  FLOAT            x, y, Z;            Coordinates  FLOAT            nx,ny, NZ;         Normals  d3dcolor <span style= "White-space:pre" ></span>   diffuse;           Diffuse color  FLOAT            u,v;               Texturecoordinates} Svertex;

As you can see, the only conflicting variable is the variable that represents the coordinates, including the normal vector (normals). A normal vector is a coordinate that is used to define a direction and can only be used in conjunction with the-Z coordinates. You need to choose which coordinates (either 2-d, or-Z) to keep and which ones to discard. If you are using 2-d coordinates, then you cannot include in-Z coordinates, or vice versa.

The only real difference between the 2-d and the-Z coordinates is the extra RHW variable, which is the reciprocal of the second coordinate (homogeneous) W. In layman's terms ( in Chinese), this generally represents the distance along the z-axis from the observer point to the vertex. In most cases, you can safely set the RHW value to 1.0.

Also note that the Svertex coordinates use the data type float (which is a floating-point value), but what is the data type of d3dcolor? D3dcolor is a DWORD value that you use to store color values in Direct3D. To construct a color value for D3dcolor, you can choose from two functions: D3dcolor_rgba or D3dcolor_colorvalue:

D3dcolord3dcolor_rgba (Red, Green, Blue, Alpha);D 3DCOLOR d3dcolor_colorvalue (Red,green, blue, alpha);

Each function (in fact, they are a macro) takes four parameters, representing the amount of each color component to be used, including an alpha value (transparency). These values can be changed from 0 to 255 in D3dcolor_rgba, while in D3dcolor_colorvalue you can change from 0.0 to 1.0 (fractions). If you are using a solid color (opaque color), then the alpha value is constant to 255 (or 1.0).

As an example, let's say you just want to include the X-y coordinates and a diffuse color component in your vertex structure:

typedef struct {  FLOAT            x, y, Z;  D3dcolor Diffuse;} Svertex;

The next step in creating your FVF is to use any combination of tags listed in table 2.3 to build the FVF descriptor.

Table 2.3 Flexible vertex Format Descriptor tags




Contains the coordinates in the Z-y.


Contains the 2-d coordinates.


Contains the normal vector (a vector).


Contains a diffuse color component.


Contains a set of texture coordinates.

To describe a FVF descriptor, you combine all the appropriate tags into a define statement (assuming you are using the-Z coordinates and the diffuse color component):

#define VERTEXFVF (d3dfvf_xyz | D3dfvf_diffuse)

Just make sure that all the tags match the ingredients you added to your vertex structure, and everything will go well.

2.4.3 using Vertex buffers ( using vertex caching )

After you construct your vertex structure and the descriptor, you create an object that contains a group of top points. Direct3D gives you two objects to use: Idirect3dvertexbuffer9 and Idirect3dindexbuffer9. The object I use in this book is Idiret3dvertexbuffer9, which stores vertices used to draw triangle columns, triangle bands, and Triangle fans. (In fact, it is associated with Idirect3dindexbuffer9 The use of combination is the way to compare efficiency, and this is the way I use it in my own updated version of the code. )

When used with a triangle column, the Idirect3dvertexbuffer9 object stores at least 3 vertices for each polygon to be drawn (these vertices are sorted in clockwise order). For a triangle band, the first polygon to be drawn uses 3 vertices, and each subsequent polygon to be drawn requires only 1 additional vertices. For triangle fans, there is a central vertex stored, and each polygon to be drawn will store two additional vertices (in fact, as long as an additional vertex, see the square example below).



A polygon can use 1, 2, or 3 vertices, depending on what graphics you are drawing. pixels require only a single vertex, a segment requires two, and a triangular polygon requires three. In this book, I mainly deal with triangular polygons.


Figure 2.11 should help you better understand how you use the stored vertices and in what order you place them. In the diagram, there is a square that can be defined in one of three ways. In the first method, you use a triangle column, so you need to define the square with 6 vertices-each of the two triangles takes three vertices.

The second method is to use a triangle band. The triangle band uses only 4 vertices, which is clearly expressed in the figure. The top three vertices construct the first polygon, and the last polygon defines the second polygon. For the third method, which is the triangular fan method, you still use 4 vertices. However, when you use a triangle fan, the first vertex you define becomes the base point of the fan, and the rest of the vertices define the slices. Creating a Vertex buffer ( Create a vertex cache )

You create a vertex cache by initializing the IDirect3DDevice9 object:

HRESULT Idirect3ddevice9::createvertexbuffer (  UINT              Length,    //# of bytes to use, in multiples                               //of Vertex structure size.  DWORD      Usage,    <span style= "White-space:pre" ></span>       //0  DWORD        FVF,            //FVF Descriptor  D3dpool   Pool,              //d3dpool_managed  Idirect3dvertexbuffer9 **ppvertexbuffer,/         / The vertex buffer  HANDLE       *phandle);      Set to NULL

The only parameter you want to change in the call to the CreateVertexBuffer function is the usage tag, which tells Direct3D how to treat the memory used to store vertex data. To stay on the safe side, you should always set the usage to 0, but if you want to improve a bit of performance, set the usage to d3dcreate_writeonly. Doing so will tell Direct3D that you are not ready to read the vertex data, and Direct3D will store the vertex data appropriately. In general, this means that vertex data is stored in the memory of the graphics hardware (called: fast read memory, faster-access memories).

This is a short example (based on the vertex format of the "Flexible vertex format" section, which uses only the-Z and diffuse vertex components), which creates a vertex cache with 4 vertices:

g_pd3ddevice = pre–initialized device object//svertex =pre-defined vertex structure//vertexfvf =pre-defined vertex F VF descriptoridirect3dvertexbuffer9*pd3dvb = NULL; Create the Vertexbufferif (FAILED (G_pd3ddevice->createvertexbuffer (                      sizeof (SVERTEX) * 4, D3dcreate_ WRITEONLY, VERTEXFVF,         d3dpool_managed, &pd3dvb, NULL))) {    //Error occurred}



When creating your own vertex caches, make sure you set the appropriate cache size (the first parameter of the CreateVertexBuffer function call). In the example shown here, you have opened up enough memory to store 4 of the vertices in a svertex format. The 4 here represents 4 instances, and Svertex is the structure you use to store your vertex data.




As before, after you run out of vertex caches, be sure to release the COM object by calling its release function.

=============================================================================== Locking the Vertex buffer ( lock vertex cache )

Before you can add vertices to the vertex cache object, you must lock the memory used by the cache. This ensures that the memory of the storage vertex is in the available memory area. Then you use a memory pointer to access the vertex cache memory. You lock the memory of the vertex cache and return a memory pointer by invoking the lock function of the cache object:

Hresultidirect3dvertexbuffer9::lock (  UINT    offsettolock,  //offset to Lock buffer, in bytes  uint    Sizetolock,    //How many bytes to lock, 0 = all  VOID **ppbdata,        //Pointer to a pointer (to access data)  DW ORD Flags);          0

Here, you let offset be in the cache where you want to access it (in bytes) and specify the number of bytes you want to access (0 for all). All you need to do is pass a pointer to the function that points to the memory pointer you will use to access the vertex cache (transformed into a void data type). The following is an example of a call that locks the entire vertex cache:

Pd3dvb =pre-intialized vertex buffer objectbyte *ptr;//Lock The vertexbuffer memory and get a pointer to Itif (FAILED (p D3dvb->lock (0,0, (void**) &ptr, 0))) {    



Vertex caches that use the d3dcreate_writeonly tag when they are created cannot be read and can only be written. If you want to read data from a vertex cache (like some functions in D3DX), you should set the usage parameter to 0 when you call the CreateVertexBuffer function.


After you end the access to the vertex cache, remember to follow the call of the Idirect3dvertexbuffer9::unlock function after each lock function call:

Hresultidirect3dvertexbuffer9::unlock ();

Unlocking a vertex cache ensures that Direct3D can begin to use it safely because it knows that you will no longer modify any of the data in that cache.

Watch out!


Make sure to minimize the amount of time between calling the lock function and calling the unlock function. The faster you handle the locked vertex cache, the better, because Direct3D must stop waiting for you to finish the vertex cache so that you can access the data it contains inside.

=============================================================================== Stuffing in Vertex data ( fill vertex )

Now you have your vertex struct, descriptor, and cache, and you've locked the cache and are ready to store the vertex data. Because you've got a data pointer to the vertex cache memory from the call to the lock function, all you have to do is copy the appropriate number of vertices into the vertex cache.

To continue my example and take advantage of the vertex format I've defined (using the-m format and the diffuse color component), I created a local set of vertex data inside an array:

Svertex Verts[4] = {  {  -100.0f, 100.0f, 100.0f, D3dcolor_rgba (255, 255,255, 255)  },  {   100.0f, 100.0f, 100.0f, D3dcolor_rgba (255, 0, 0,255)  },  {   100.0f, -100.0f, 100.0f, D3dcolor_rgba (0, 255, 0,255)  },  {  -100.0f,  -100.0f, 100.0f, D3dcolor_rgba (0, 0, 255, 255)};

Lock the vertex cache so that you get a pointer to the vertex cache memory and then copy the local vertex data (and unlock the vertex cache after it's done):

Pd3dvb =pre-initialized vertex buffer objectbyte *ptr; Lock the VertexBuffer memory and get a pointer to Itif (SUCCEEDED (Pd3dvb->lock (0,0, (void**) &ptr, 0))) {   // Copy local vertices into vertex buffer  memcpy (PTR, Verts, sizeof (Verts));   Unlock the vertex buffer  pd3dvb->unlock ();}

This is all you need to do to build a vertex cache and expect you to populate the vertex data! To use vertex information, you now only need to specify a stream source and a vertex renderer (vertex shader).

2.4.4 Vertex Streams ( vertex stream )

Direct3D allows you to feed the vertex to the (feed to) renderer (renderer) through a series of different streams-called vertex streams (vertex streams). You can create very impressive results by consolidating the vertex data of multiple streams into a single stream, but in this book I just use a stream, because the complexity of using multiple streams is beyond the scope of this book.

In order to copy your vertex data into a stream, you use the Idirect3ddevice9::setstreamsource function:

Hresultidirect3ddevice9::setstreamsource (  UINT    streamnumber,       //0  idirect3dvertexbuffer9* Pstreamdata,     //Vertex Buffer object  UINT    offsetinbytes,          //Offset (in bytes) of Vertex data                                                     //in The vertex buffer.  UINT    Stride);                        Size of Vertexstructure

All you have to do now is set the vertex stream source (vertex stream sources) to call this function and pass a pointer to the vertex cache object, providing the number of bytes used to store the vertex structure (using sizeof).

If you store an extra set of polygons (such as several triangle bands) in the vertex cache, you can set the Offsetinbytes parameter to offset of the vertex data. For example, if I use a vertex cache to store two triangle bands (the first triangle is at offset 0 and the second triangle is at offset 6), then I set the appropriate offset (in this case, The second triangle band has an offset of 6 to draw a second triangle band.

Starting with the example of storing vertices in the vertex cache in the previous section, you can use the following method:

g_pd3ddevice–pre-initialized device object//pd3dvb =pre-initialized vertex bufferif (FAILED (g_pd3ddevice-> SetStreamSource (0,pd3dvb,                         0, sizeof (Svertex))) {    //Error occurred}

2.4.5 Vertex Shaders ( vertex shader )

As the final step in drawing a graph using vertices, you need to understand the concept of vertex shaders. The vertex shader (vertex shader) is a mechanism that manipulates the loading and processing of vertices, including changing vertex coordinates, applying color and atomization functions, and many other vertex components.

A vertex shader can appear in two ways. It can be a fixed vertex shader (all the functions used to complete the general function are already built-in), or it can be programmable (programmable) vertex shader (where you can customize a function to change vertex information before rendering to the display).

Try to explain that the programmable vertex shader is beyond the scope of this book. (However, I have been using the updated version of the code HLSL programmable vertex shader for language writing. instead, I focus on using fixed vertex shaders because they contain all the functionality you need. you may think it's enough for a decade ago, but it's not enough for the next generation of us who have played a lot of cool games. )

To use a fixed vertex shader on your vertex, you pass the FVF descriptor of your custom vertex to the IDIRECT3DDEVICE9::SETFVF function:

HRESULTIDIRECT3DDEVICE9::SETFVF (  DWORD        FVF);         Vertex FVF Descriptor

Using the previous function is as simple as the following:

g_pd3ddevice =pre-initialized device object//vertexfvf =pre-defined vertex FVF descriptorif (FAILED (g_pd3ddevice- >SETFVF (VERTEXFVF)) {    //Error occurred}

You have now set up the vertex information. The next step is to establish the various transformations needed to place the vertices (in local space) into their world space coordinates. Of course, you only need this step when you are using the-Z coordinates.


Well, the contents of these sections are finally finished. Perhaps the reader is not very clear, especially the meaning of the specific parameters of the function. In fact, you can refer to the SDK documentation, or refer to the second edition of Dragon Book. In addition, the method used here to set the vertex is not used in my updated version of the code, but with the second version of the Dragon book more advanced, more flexible way, so see not very understand also has no relationship.

DirectX 9.0c Game Development notes of RPG programming self-learning log eight--drawing with DirectX graphics (drawing with DirectX graphic) (4th) (A)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.