Using Mesh in DirectX9.0 (1)

xiaoxiao2021-03-06  121

10. Mesh Part One

This article translated from "Introduction to 3D Game Programming WITH DIRECTX 9.0" Chapter 10 "Mesh Part One", please ax.

In D3DX, there are many functions that use ID3DXMESH interfaces, such as D3DxCreate *. The main feature of the ID3DXMESH interface inherits from the ID3DXBasemesh parent interface, and other Mesh interfaces are also inherited from the ID3DXBasemesh interface, such as ID3DXPMESH interface, this interface is used for Progressive Mesh, translating it into "gradually enters Mesh", and I don't know if it is appropriate.

The goal to achieve this section:

l Learning the internal data organization of ID3DXMESH objects

l Learn to create an ID3DXMESH object

l learning optimized id3dxmesh

l Learning to render ID3DXMESH

10.1. Geometry Information

The interface ID3DXBasemesh has a vertex buffer and vertex index buffer, which are used to store the vertex data of the Mesh and the index data of the vertex, and the two are combined to render the triangle of Mesh. Use the two methods below to get pointers to two buffers:

HRESULT ID3DXMESH :: GETIRECTEXBUFFER (LPDirect3dvertExBuffer9 * PPVB); HRESULT ID3DXMESH :: getIndexbuffer (LPDIRECT3DINDEXBUFFER9 * PPIB);

Below is an example of the above two method usage:

Idirect3dvertExbuffer9 * pvb = null; mesh-> getvertexbuffer (& pvb); idirect3dindexbuffer9 * pib = null; mesh-> getIndexbuffer (& PIB);

Also, if you want to modify the vertex buffer and vertex index buffer, you need to lock the following two methods:

HRESULT ID3DXMESH :: LockvertExBuffer (DWORD FLAGS, LPVOID * PPDATA); HRESULT ID3DXMESH :: LockIndexBuffer (DWORD FLAGS, LPVOID * PPDATA);

Parameter Flags is used to explain the locking mode, and the parameter PPDATA returns the address of the locked memory. Remember, if the lock is successful, you need to call the unlock function of the pairing:

HRESULT ID3DXMESH :: unlockvertexbuffer (); HRESULT ID3DXMESH :: UnlockIndexBuffer ();

Below is another method of ID3DXMESH interface related to Mesh geometry:

l DWORD getfvf (); - return to the vertex format

l DWORD getNumvertices (); - Return to the number of vertices in the vertex buffer

l DWORD getNumBytespervertex (); - Returns a number of bytes occupied by a vertex

l DWord getnumface (); - Returns the number of faces of MESH, that is, the number of triangles

10.2. Subset and attribute buffer

A MESH consists of several subsets. The subset is a triangle that uses the same property rendered in Mesh. The attribute here refers to the material, texture, rendering state. Each subset of unique non-negative integers indicates its ID, such as 0, 1, 2, 3, etc.

Each triangle in the MESH is associated with an attribute ID, indicating that the triangle belongs to the subset. For example, in a MESH indicating the house, the triangle constituting the floor has an attribute ID 0, which means that these triangles belong to subset 0; the same, a triangular attribute ID of the forming wall is 1, they belong to a subset 1. The triangle property ID is stored in the property buffer in the Mesh, which is a DWORD array. Because each faces in the attribute buffer, the number of items in the property buffer is equal to the number of faces in the MESH. The items in the property buffer and the index buffer defined triangle correspond to one or one; Triangle I has the index item definition of the following three index buffers:

A = i * 3

B = i * 3 1

C = i * 3 2

You can access the property buffer using the following method:

DWORD * Buffer = NULL; Mesh-> LockAttributeBuffer (LockingFlags, & Buff); // Do Something ... Mesh-> unlockattributeBuffer ();

10.3. Rendering

Interface ID3DXMESH provides a DrawSubset method to render each triangle in the subset of parameter AttribID indicated. For example, if all triangles in the subset 0, the following methods can be used:

Mesh-> Drawsubset (0);

If you want to render the entire mesh, you need to render each subset of Mesh. Because the subset sequence corresponds to the material, texture sequences used in Mesh, that is, the i and the material, the I II of the texture array corresponds, so a simple loop rendering Mesh:

For (int i = 0; i setMaterial (mtrls [i]); device-> settexture (0, Textures [i]); Mesh-> DrawSubset (i);

10.4. Optimization

To make more effective rendering Mesh, you can renew the vertices and indexes, that is, Optimize Mesh. You can use the following method to optimize:

HRESULT ID3DXMESH :: OptimizeInplace (DWORD FLAGS, Const DWORD * Padjacencyin, DWORD * PADJACENCYOUT, DWORD * PFACEREMAP, LPD3DXBUFFER * PPVERTEXREMAP);

l Flags - Optimization Option tells this method to perform what type of optimization. One or more values ​​below can be district:

n D3DXMeshopt_Compact - Delete Useless Vertices and Index items

n d3dxmeshopt_attrsort - Sort by the attribute to triangle and adjust the property table, which will make the DrawSubset method more efficiently

N D3DXMeshopt_vertexcache - Increase the hit rate of vertex buffering

n D3DXMeshopt_stripreorder - Reorganization Vertex index whose triangle strip is as long as possible

n d3dxmeshopt_ignoreverts - only optimize index, ignore vertices

l Padijacencyin - an array of neighboring Mesh

l Padjacencyout - an array of adjacency information of an optimized MESH. This DWORD array must have ID3DXMESH :: getnumface () * 3 elements. If this information is not required, NULL can be passed. l PFAceremap - A DWORD array for receiving surface reloading information. This array should not be less than ID3dxmesh :: getnumfaces (). When Mesh is optimized, the surface defined by the index buffer may be moved, that is, if the PFACEREMAP of the PFAceRemap indicates the ventriode value that is moved to the i-th original surface. If this information is not required, you can use NULL.

l PPVERTEXREMAP - points to the address of the pointer of the id3DXBuffer, returns the vertex retransmission information. The buffer should contain id3dxmesh :: getnumvertices () top points. When Mesh is optimized, the vertex may be moved, which means that the original vertex is moved to a new location, that is, PPVERTEXREMAP's reference indicates a new location of the original i-th top. If this information is not required, you can use NULL.

// Get the adjacency info of the non-optimized mesh DWORD adjacencyInfo [Mesh-> GetNumFaces () * 3];. Mesh-> GenerateAdjacency (0.0f, adjacencyInfo);. // Array to hold optimized adjacency info DWORD optimizedAdjacencyInfo [Mesh -> getnumface () * 3]; Mesh-> OptimizeInplace (D3DXMeshopt_Aattrsort | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VOMPACT | D3DXMESHOPT_VERTEXCACHE, AdjacencyInfo, OptimizedAdjacencyInfo, 0, 0);

Another similar approach is Optimize (), which outputs an optimized mesh instead of optimization on the basis of Mesh:

HRESULT ID3DXMESH :: Optimize (DWORD FLAGS, Const DWORD * Padjacencyin, DWORD * PADJACENCYOUT, DWORD * PFACEREMAP, LPD3DXBUFFER * PPVERTEXREMAP, LPD3DXMESH * PPOPTMESH);

10.5. Property

If a MESH uses the D3DXMeshopt_attrsort flag to optimize, the structural information of Mesh will be sorted by attribute, so that the vertex / vertex index of each subset will form a continuous block.

In addition to the sorting of geometric information, the D3DXMeshopt_attrsort optimization option will also create a property sheet. The table is an array of D3DXAttributeRAnge structures, each of which corresponds to a subset of Mesh and an continuous block of the vertex / vertex index, which is included in this block. The definition of structural D3DXATRIBUTERANGE is as follows:

TypeDef strung; dword facutart; dword facecount; dword vertexstart; d3dxattributeRAnge;

l attribid - Id of subset

l FacStart - The start value of the subset, Facestart * 3 is the beginning of the three-pointed index of the index buffer, the number of faces in the subset, that is, the triangular number

l VertexStart - Offset of the starting vertex of the subset in vertex buffer

l Vertexcount - the number of fixed points included in this subset

It is easy to see the connection between the structure and the information represented in the above figure. Each of the attribute tables in the figure above corresponds to a subset.

After building a property sheet, rendering a subset is easy, just check the property table to find your own geometric information. If there is no property sheet, each rendering of a subset requires a linear search for the property buffer to find the geometric information contained in the subset.

You can use the following method to access Mesh property sheet:

HRESULT ID3DXMESH :: GetAttributeTable (D3DXATTRIBUTERANGE * PATTRIBTABLE, DWORD * PATTRIBTABLESIZE);

This method can complete two functions: the number of properties of the property table can be returned, or the complete property table can be returned.

To get the number of elements of the property, you can pass null, such as:

DWORD NUMSUBSETS = 0; Mesh-> GetAttributeTable (0, & NUMSUBSETS);

Then you can get the property table:

D3DXATTRIBUTERANGE TABLE = New D3DXATTRIBUTERANGE [NUMSUBSETS]; Mesh-> GetAttributeTable (Table, & NumSubset);

You can also directly modify the properties table directly using the ID3DXMESH :: SetAttributeTable method.

D3DXATRIBUTERANGE AttributeTable [12]; // ... Fill AttributeTable Array with Data Mesh-> SetAttributeTable (AttributeTable, 12);

10.6. Adjacent information

For some operations of Mesh, such as optimization, you need to know adjacency information between triangularities, while the neighbor array of Mesh stores such information.

The adjacent array is an array of DWORD types, each of which corresponds to a triangle in MESH. For example, the triangle corresponding to the I Item of the adjacent array has the following three index values:

A = i * 3

B = i * 3 1

C = i * 3 2

Here, Ulong_MAX = 4294967295 indicates that there is no adjacent triangle. In fact, this is -1.

Since each triangle has three sides, he has three adjacent triangles.

Therefore, each triangle may have three adjacent triangles, and the adjacent array must have (ID3DXMESH :: GetNumFaces () * 3) element.

In D3DX, there are many functions that can output Mesh's neighboring information, such as:

HRESULT ID3DXMESH :: GeneRateAdjacency (Float Fepsilon, DWORD * PADJACENCY);

l Fepsilon - Indicates that when two points are more, it can be considered a point. When the distance between the two points is less than Epsilon, they can think they are the same point.

l Padjacency - an adjoint array for storing adjacency information

E.g:

DWord AdjacencyInfo [Mesh-> getnumface () * 3]; Mesh-> GenerateAdjacency (0.001F, AdjacencyInfo); 10.7. Clone

Sometimes, you need to copy the data of Mesh, you can use the ID3DXMESH :: CloneMeshfvf method:

HRESULT ID3DXMESH :: Clonemeshfvf (DWORD OPTIONS, DWORD FVF, LPDIRECT3DDEVICE9 PDEvice, LPD3DXMESH * PPCLONEMESH);

l Options - Create a sign of a mesh. The full information can be referred to the SDK document. The following are very common:

N D3DXMESH_32BIT - Use 32-bit vertex index

N D3DXMESH_MANAGED -MESH data will be placed in a controlled memory buffer pool

n d3dxmesh_writeonly -men data can only perform a write operation, can not perform a read operation

N D3DXMESH_DYNAMIC -MESH buffer will be dynamic

l FVF - Creating a new mesh flexible fixed point format

l PDEvice - D3D device associated with clone mesh

l ppclonemesh - output new mesh

This method allows you to specify different options and FVFs from the original Mesh. For example, now there is a fixed-point format for the Mesh of D3DXFVF_XYZ, we want to copy a vertex format for the Mesh of D3DXFVF_XYZ | D3DXFVF_NORMAL, you can do this:

// assume _mesh and device are valid ID3DXMesh * clone = 0; Mesh-> CloneMeshFVF (Mesh-> GetOptions (), // use same options as source mesh D3DFVF_XYZ | D3DFVF_NORMAL, // specify clones FVF Device, & clone);

10.8. Create Mesh (D3DxCreateMeshfvf)

We can create an empty Mesh object using the D3DxCreateMeshfvf function. The so-called empty means that we have specified the number of vertices and the number of faces (that is, the number of triangles), and the function D3DxCreateMeshfvf also assigns the appropriate size memory to the vertices, fixed-point indexes, and attribute buffers. With these buffers, you can manually fill the context data (need to provide fixed-point buffer, index buffer, attribute buffer, respectively).

HRESULT WINAPI D3DXCREATEMESHFVF (DWord Numface, DWORD NUMVERTICES, DWORD OPTIONS, DWORD FVF, LPDIRECT3DDEVICE9 PD3DDEVICE, LPD3DXMESH * PPMESH);

l Numfaces -mesh number of triangles must specify a number of more than 0

l Numvertices - Diendal, must also be a number greater than 0

l Options - Create a Mesh option flag, the commonly used flags are as follows:

N D3DXMESH_32bit -mesh uses 32-bit vertex index

N D3DXMESH_MANAGED - Using a controlled memory pool

N D3DXMESH_WRITEONLY -MESH data can only be written, can not be read N D3DXMESH_DYNAMIC - use dynamic buffering

l Fvf -mesh vertex format

l PD3DDEVICE - D3D device associated with mesh

l ppmesh - output Mesh pointer

In the next section, the usage of the function will be exemplified, and the data of the MESH object will be manually populated.

Alternatively, you can use the D3DXCREATEMESH function to create an empty Mesh object. The prototype is as follows:

HRESULT WINAPI D3DXCREATEMESH (DWord Numface, DWORD NUMVERTICES, DWORD OPTIONS, Const LPD3DVERTEXELEMENT9 * PDECLATION, LPDIRECT3DDEVICE9 PD3DDEVICE, LPD3DXMESH * PPMESH);

The meaning of the parameters does not need to be explained, and they are similar to the parameters of D3DxCreateMeshfvf. However, the fourth parameter is an array of D3DVertexElement9 instead of the previous FVF.

10.9. Application example: Create and render Mesh

We manually create a cube that will use most of the knowledge points discussed in this chapter:

l Create an empty mesh

l Fill in the geometric information of cubes in Mesh

l

l Generate the neighboring information of MESH

l Optimization

l Rendering

Here, give the code framework, this example uses the D3DxCreateMeshfvf function to create a Mesh object.

In the code, define the overall variables as follows:

ID3DXMESH * MESH = 0; const dword number = 3; iDirect3dtexture9 * textures [3] = {0, 0, 0}; // Texture for Each Subset

The first is a pointer to the Mesh object; there are three subsets in the Mesh object. Each subset uses different texture rendering, and the array texTures stores the texture of each subset.

The main code is in the setup function, he first created an empty Mesh object:

Bool setup () {HRESULT HR = 0; hr = d3dxcreatemeshfvf (12, 24, d3dxmesh_managed, vertex :: fvf, device, & mesh);

Here, the created MESH has 12 faces (triangles), 24 top points, and use them to describe cubes.

Now, the Mesh object is still empty, which needs to fill the appropriate vertex / index data for it.

// Fill in Vertices of a Box Vertex * V = 0; Mesh-> LockvertExbuffer (0, (void **) & v); // Fill in The Front Face Vertex Data V [0] = Vertex (-1.0f, - 1.0F, -1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F); v [1] = Vertex (-1.0F, 1.0F, -1.0F, 0.0F, 0.0F, -1.0 F, 0.0F, 1.0F);.. V [22] = Vertex (1.0F, 1.0F, 1.0F, 1.0F, 0.0F, 0.0F, 1.0F, 1.0F); V [23] = Vertex (1.0F, -1.0F, 1.0F, 1.0F, 0.0F, 0.0F, 0.0F); Mesh-> unlockvertexbuffer (); // define the Triangles of the Box Word * i = 0; Mesh- > LockIndexBuffer (0, (void **) & i); // Fill in the Front Face Index Data i [0] = 0; i [1] = 1; i [2] = 2; i [3] = 0; i [4] = 2; i [5] = 3;.... // Fill in the right face index data i [30] = 20; i [31] = 21; i [32] = 22; i [33 ] = 20; i [34] = 22; i [35] = 23; Mesh-> unlockindexbuffer (); After the cube's geometric information is completed, it is necessary to divide a subset of individual triangles. You can specify the subset of each triangle belonging by modifying the properties buffer of the Mesh object. In this example, in the 12 triangles defined by the index buffer, the first four belong to the subset 0, then the following four belongs to the subset 1, and finally four belong to subset 2.

DWORD * AttributeBuffer = 0; Mesh-> LockAttributeBuffer (0, & AttributeBuffer); for (int A = 0; a <4; a ) // Triangles 1-4 AttributeBuffer [A] = 0; // Subset 0 for (INT B) = 4; B <8; B ) // Triangles 5-8 AttributeBuffler [B] = 1; // Subset 1 for (int C = 8; C <12; C ) // Triangles 9-12 AttributeBuffer [C] = 2; // Subset 2 Mesh-> UnlockAttributeBuffer ();

Here, this Mesh object has been created and can be rendered. However, it has not been optimized. Of course, for this negligible cube, it is optimized that there is no benefit, but we still use it to demonstrate the usage of the ID3DXMESH interface method. Before optimization, you need to calculate the neighboring information of the Mesh object:

Std :: Vector AdjacencyBuffer (Mesh-> getnumface () * 3); Mesh-> GenerateAdjacency (0.0F, & AdjacencyBuffer [0]);

Then, perform an optimization: hr = mesh-> OptimizeInplace (D3DXMeshopt_Aattrsort | D3DXMeshopt_Compact | D3DXMeshopt_vertexcache, & adjacencybuffer [0], 0, 0, 0);

Here, the work of creating a Mesh object has been completed. Finally, if everything goes well, the function setup should return True:

Return True;} // end setup ()

The above is said, and the Mesh object will establish a property sheet. Use the following code to verify.

// number of entries in the attribute table DWORD numEntries = 0; mesh-> GetAttributeTable (0, & numEntries); vector table (numEntries); mesh-> GetAttributeTable (& table [0], & numEntries); for (int i = 0; i

Below is some of the output information:

Entry 0 ------------ Subset ID: 0 Face Start: 0 Face Count: 4 Vertex Start: 0 Vertex Count: 8 Entry 1 ----------- Subset ID : 1 Face Start: 4 Face Count: 4 Vertex Start: 8 Vertex Count: 8 Entry 2 ------------ Subset ID: 2 Face Start: 8 Face Count: 4 Vertex Start: 16 Vertex Count : 8

Consistent with the previous design. Finally, rendering the Mesh object:

Device-> Clear (0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFER, 0X00000000, 1.0F, 0); device-> Beginscene (); for (int i = 0; i settexture) {device-> settexture (0, Textures [I]); Mesh-> Drawsubset (i);} device-> endscene (); device-> present (0, 0, 0, 0); 10.10. summary

l Mesh objects contain vertices, indexes, and property buffers. The vertex and index buffers contain the geometric information of the Mesh object. Each of the property buffer corresponds to a triangle of a Mesh object, indicating the subset of the triangle belonging.

l Mesh objects can be optimized using OptimizeInPlace and Optimize method. In order to be rendered more efficiently, optimize the geometric information of the reorganization of Mesh. Use the D3DXMeshopt_attrsort flag to optimize, generate a property sheet, where you access a property sheet, you can completely render a subset.

l Mesh object The neighboring information is a DWORD array, and each triangle has three adjacent connections, representing a triangle adjacent to the triangle.

l You can create an empty Mesh object using the D3DxCreateMeshfvf function. Then use the corresponding Lock * method to fill in the appropriate data into the geometric information and attribute information of the MESH.

转载请注明原文地址:https://www.9cbs.com/read-125573.html

New Post(0)