Chapter 2
The id3dxbuffer interface is a generic data structure that is used by the d3dx database and can store data in a continuous memory block.
This interface has only two methods
Lpvoid getbufferpointer (); returns the pointer to the starting position of data in the cache.
DWORD getbuffersize (); return the cache size, in bytes
To ensure the versatility of this interface, this interface uses a void pointer. Therefore, we must implement the data type to be stored.
Example:
The d3dxloadmeshfromx function returns the adjacent information of a grid object with a pointer of the id3dxbuffer type.
Because the adjacent information is stored in a DWORD array, when we want to use the adjacent information of this interface, we must forcibly convert the cache type.
Example:
DWORD * info = (DWORD *) adjacencyinfo-> getbufferpointer ();
D3dxmaterial * mtrls = (d3dxmatrial *) mtrlbuffer-> getbufferpointer ();
Because id3dxbuffer is a COM object, the interface must be released after use to prevent memory leakage.
Adjacencyinfo-> release ();
Mtrlbuffer-> release ();
We can use the following function to create an empty id3dxbuffer object.
Hresult d3dxcreatebuffer (DWORD numbytes, lpd3dxbuffer * ppbuffer );
Create a cache that can hold 4 data records
Id3dxbuffer * buffer = 0;
D3dxcreatebuffer (4 * sizeof (INT), & buffer );
The. x format is the DirectX-defined format, which is strongly supported by the d3dx library. The d3dx Library provides functions for loading and saving XFile files.
This method creates an id3dxmesh object and loads the geometric data in XFile to this object.
Hresult d3dloadmeshfromx (lpcstr pfilename,
DWORD options,
Lpdirect3ddevice9 pdevice,
Lpd3dxbuffer * ppadjacency,
Lpd3dxbuffer * ppmaterials,
Lpd3dxbuffer * ppeffectinstances,
Pdword pnummaterials,
Lpd3dxmesh * ppmesh );
# Pfilename XFile file name
# Options creation tag used when creating a grid
* The d3dxmesh_32bit mesh uses a 32-bit index.
* D3dxmesh_managed the grid data will be stored in the managed memory pool.
* D3dxmesh_writeonly specifies that the grid data bit is read-only.
* D3dxmesh_dynamic the grid cache uses dynamic memory
# Pdevice device pointer related to the Grid Object
# Ppadjacency returns an id3dxbuffer object, which contains a DWORD array describing the adjacent information of the Grid Object
# Ppmaterials returns an id3dxbuffer object, which contains a d3dxmaterial structure array that stores the material data of the mesh.
# Ppeffectinstances returns an id3dxbuffer object that contains a D3DXEFFECTIN-STANCE Structure
# Pnummaterials returns the number of materials in the mesh (that is, the number of elements in the d3dxmaterial array output by ppmaterials)
# Ppmesh returns the id3dxmesh object created with the XFile geometric data filled
The 7th parameters in the d3dxloadmeshfromx function return the number of materials contained in the grid object, and the 5th parameters return a structure array of the d3dxmatrial type that stores the material data.
Typedef struct d3dxmaterial {
D3dmaterial9 matd3d;
Lpstr ptexturefilename; // specifies the file name of the grid-related texture.
} D3dxmaterial;
The XFile file does not store texture data and only contains the texture image file name. This file name is a reference to the texture image that contains the actual texture data, after an XFile is loaded using the d3dxloadmeshfromx function, texture data must be loaded Based on the specified texture file name.
After the d3dxloadmeshfromx function loads XFile data, the items I in the returned d3dxmaterial structure array correspond to the subset I. All the subsets are divided into 0, 1, 2 ,... n-1 is marked in order, where N is the total number of subsets and materials. In this way, you can use a simple loop to traverse and draw all subsets to complete the painting of the entire grid.
Example:
Id3dxmesh * mesh = 0;
STD: vector <d3dmaterial9> mtrls (0 );
STD: vector <idirect3dtexture9 *> textures (0 );
Mesh Object Storage grid data loaded from XFile
The setup function that records the XFile file.
Bool setup ()
{
Hresult hR = 0;
Id3dxbuffer * adjbuffer = 0;
Id3dxbuffer * mtrlbuffer = 0;
DWORD nummtrls = 0;
HR = d3dxloadmeshfromx ("bigship1.x ",
D3dxmesh_managed,
Device,
& Adjbuffer,
& Mtrlbuffer,
0,
& Nummtrls,
& Mesh );
If (failed (HR ))
{
: MessageBox (0, "d3dxloadmeshfromx ()-failed", 0, 0 );
Return false;
}
// After loading XFile data, you must traverse the elements in the d3dxmaterial array and load the texture data referenced by the grid.
If (mtrlbuffer! = 0 & nummtrls! = 0)
{
D3dxmaterial * mtrls = (d3dxmaterial *) mtrlbuffer-> getbufferpointer ();
For (INT I = 0; I <nummtrls; I ++)
{
// The matd3d property does't have an ambient value set
// When its loaded, so set it now
Mtrls [I]. matd3d. Ambient = mtrls [I]. matd3d. Diffuse;
// Save the ith Material
Mtrls. push_back (mtrls [I]. matd3d );
// Check if the ith material has an associative texture
If (mtrls [I]. ptexturefilename! = 0)
{
// Yes load the texture for the ith subset
Idirect3dtexture9 * Tex = 0;
D3dxcreatetexturefromfile (device, mtrls [I]. ptexturefilename, & Tex );
// Save the loaded texture
Textures. push_back (Tex );
}
Else
{
// No texture for the ith subset
Textures. push_back (0 );
}
}
}
D3d: Release <id3dxbuffer *> (mtrlbuffer );
Return true;
}
In the display function, the mesh is slightly rotated in each frame of the image to show the animation effect of rotation, because the subsets of the mesh are 0, 1, 2... N-1 sequence mark (n is the total number of subsets). The whole grid can be drawn through a simple loop.
Bool display (float timedelta)
{
If (device)
{
Static float y = 0.0f;
D3dxmatrix yrot;
D3dxmatrixrotationy (& yrot, y );
Y + = timedelta;
If (Y> = 6.28f)
Y = 0.0f;
D3dxmatrix world = yrot;
Device-> settransform (d3dts_world, & World );
Device-> clear (0, 0, d3dclear_target | d3dclear_zbuffer, 0 xffffffff, 1.0f, 0 );
Device-> beginscene ();
For (INT I = 0; I <mtrls. Size (); I ++)
{
Device-> setmaterial (& mtrls [I]);
Device-> settexture (0, textures [I]);
Mesh-> drawsubset (I );
}
Device-> endscene ();
Device-> present (0, 0, 0, 0 );
}
Return true;
}
We can use the following method to generate the vertex method vector of any mesh:
Hresult d3dxcomputenormals (lpd3dxbasemesh pmesh, // mesh to compute the normals
Const DWORD * padjacency // input adjacency info
);
This function uses the mean method of the normal vector to generate the normal vector of the vertex. If the adjacent information is provided, the overlapping vertex will be removed. If the adjacent information is not provided, then, the method vector of the overlapped vertex is obtained by obtaining the average value of the local method vector of each plane attached to the vertex. It is important that the input parameter pmesh vertex format must contain the mark d3dfvf_normal
If the XFile library does not contain vertex normal data, the id3dxmesh mesh object created by the function d3dxloadmeshfromx does not contain the d3dfvf_normal mark in its vertex format. Therefore, you must clone the grid before using the d3dxcomputenormals function, specify a vertex format that contains the d3dfvf_normal mark.
Example:
If (! (Pmesh-> getfvf () & d3dfvf_normal ))
{
Id3dxmesh * ptempmesh = 0;
Pmesh-> clonemeshfvf (
D3dxmesh_managed,
Pmesh-> getfvf () | d3dfvf_normal, // Add it here
Device,
& Ptempmesh );
// Compute the normals
D3dxcomputenormals (ptempmesh, 0 );
Pmesh-> release (); // get rid of the old Mesh
Pmesh = ptempmesh; // Save the new mesh with normals
}
The progressive mesh is represented by the id3dxpmesh interface. It allows you to use a series of edge collapse transformations (ECT) to simplify the mesh. Each ect removes one vertex and one or two faces, since each ECT is reversible (its inverse operation is called vertex split), you can reverse the simplified process to precisely restore the mesh to its initial state. Of course, this means that we cannot obtain more details than the original mesh. We can only simplify the mesh and perform inverse operations.
The idea of progressive mesh is similar to that of hierarchical progressive texture in textures.
Hresult d3dxgeneratepmesh (
Lpd3dxmesh pmesh,
Const DWORD * padjacency,
Const d3dxattributewihts * pvertexattributeweights,
Const float * pvertexweights,
DWORD minvalue,
DWORD options,
Lpd3dxpmesh * pppmesh );
# Pmesh the input variable contains grid data. The progressive grid will be generated based on this grid.
# Padjacency refers to an array pointer of the DWORD type that contains the neighbor information of pmesh.
# Pvertexattributeweights points to the d3dxattributeweights structure array pointer. the dimension of this array is pmesh-> getnumvertices (). The I entry of this array corresponds to the I vertex in pmesh, the attribute weight of the corresponding vertex is specified. The vertex attribute weight is used to determine the probability that the vertex is removed during the simplification process. null can be input for the parameter, each vertex is assigned the default Attribute Weight.
# Pvertexweights points to a pointer to a float array. the dimension of this array is pmesh-> getnumvertices (). The I entry of this array corresponds to the I vertex in pmesh, the weight of the corresponding vertex is specified. The higher the weight of a vertex, the smaller the probability of being removed during the simplification process. You can assign this parameter to null, in this way, each vertex is assigned a default vertex weight of 1.0.
# The number of vertices or patches in the minvalue mesh (determined by the options parameter) can be simplified to the lower limit. This value is only an expected value, the actual vertex or attribute weights are also dependent, so the simplified structure may be inconsistent with the value.
Options this parameter is actually a member of the d3dxmeshsimp Enumeration type.
* D3dxmeshsimp_vertex specifies that the preceding parameter minvalue indicates the number of vertices.
* D3dxmeshsimp_face specifies the number of patches with the preceding parameter minvalue.
Pppmesh returns the generated progressive grid.
The vertex weight structure allows you to specify a weight for each possible component of the vertex. If the weight of a component is 0.0, it indicates that the weight is not authorized, the higher the weight of the vertex component, the smaller the probability that the vertex will be removed during the simplification process.
Vertex weight structure:
Typedef struct d3dxattributeweights {
Flaot position;
Float boundary;
Float normal;
Float diffuse;
Float specular;
Float texcoord [8];
Float tangent;
Float binormal;
} D3dxattributeweights, * lpd3dxattributeweights;
D3dxattributeweights attributeweights;
Attributeweights. Position = 1.0;
Attributeweights. Boundary = 1.0;
Attributeweights. Normal = 1.0;
Attributeweights. Diffuse = 0.0;
Attributeweights. specular = 0.0;
Attributeweights. Tex [8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
Default value is recommended.
Id3dxpmesh interface:
DWORD getmaxfaces (void); returns the maximum number of progressive mesh patches that can be specified
DWORD getmaxvertices (void); returns the maximum number of vertices that can be specified for a progressive mesh.
DWORD getminfaces (void); return the lower limit that can be specified for the number of progressive mesh Patches
DWORD getminvertices (void); returns the lower limit that can be specified for the number of vertices in the progressive mesh.
Hresult setnumfaces (DWORD faces); allows us to set the number of mesh slices that can be simplified or refined
For example, the mesh currently has 50 tabs, which are simplified to 30
Pmesh-> setnumfaces (30 );
After adjustment, the number of mesh faces may be different from the expected number of faces. If faces is smaller than getminfaces (), getminfaces () is used. Similarly, faces is greater than getmaxfaces, getmaxfaces ();
Hresult setnumvertices (DWORD vertices); this method allows us to set the number of vertices in the mesh to be simplified or refined.
For example, the grid currently has 20 vertices. add details and increase the number of vertices to 40.
Pmesh-> setnumvertices (40)
After adjustment, the number of mesh vertices may be different from the expected number of vertices. The rule is similar to the setnumfaces rule.
Hresult trimbyfaces (
DWORD newfacesmin,
DWORD newfacesmax,
DWORD * rgifaceremap, // face remap info
DWORD * rgivertremap // vertex remap info
);
This method allows you to reset the newfacesmin and newfacesmax values within [getminfaces (), getmaxfaces, this function also returns the re-painting information of the patches and vertices.
Hresult trimbyvertices (
DWORD newverticesmin,
DWORD newverticesmax,
DWORD * rgifaceremap,
DWORD * rgivertremap );
This method allows you to reset the newverticesmin and newverticesmax values within [getminvertices (), getmaxvertices, this function also returns the re-painting information of the patches and vertices.
The setnumfaces and setnumvertices methods allow you to adjust the SLS of a grid.
In the following example, the mesh created and drawn is a progressive mesh represented by the id3dxpmesh interface.
Id3dxmesh * sourcemesh = 0;
Id3dxpmesh * pmesh = 0;
Vector <d3dmaterial9> mtrls (0 );
Vector <idirect3dtexture9 *> textures (0 );
To generate a progressive mesh, you must pass in a "Source" mesh that contains the data to be included in the created progressive mesh. Therefore, you must first load the XFile data to an id3dxmesh object sourcemesh, then generate a progressive grid.
Bool setup ()
{
Hresult hR = 0;
// Load the XFile data
// Extracting materials and textures snipped
// Generate a progressive Grid
// Generate the progressive Mesh
HR = d3dxgeneratepmesh (
Sourcemesh,
(DWORD *) adjbuffer-> getbufferpointer (),
0,
0,
1,
D3dxmeshsimp_face,
& Pmesh );
D3d: Release <id3dxmesh *> (sourcemesh );
D3d: Release <id3dxbuffer *> (adjbuffer );
If (failed (HR ))
{
: MessageBox (0, "d3dxgeneratepmesh ()-failed", 0, 0 );
Return false;
}
}
If you want to simplify the mesh to only one surface, it is impossible to implement this because of the existence of vertex/attribute weights.
However, set the expected number of patches to 1 to simplify the mesh to the lowest resolution possible.
Since the mesh is first drawn with the maximum resolution, this setting is as follows:
DWORD maxfaces = pmesh-> getmaxfaces ();
Pmesh-> setnumfaces (maxfaces );
Bool display (float timedelta)
{
If (device)
{
// Update: mesh resolution
// Get the current number of faces the pmesh has
Int numfaces = pmesh-> getnumfaces ();
// Add a face, note the setnumfaces () will automatically
// Clamp the specified value if it goes out of bounds
If (: getasynckeystate ('A') & 0x8000f)
{
Pmesh-> setnumfaces (numfaces + 1 );
If (pmesh-> getnumfaces () = numfaces)
Pmesh-> setnumfaces (numfaces + 2 );
}
// Remove a face, note the setnumfaces () will automatically
// Clamp the specified value if it goes out of bounds
If (: getasynckeystate ('s ') & 0x8000f)
Pmesh-> setnumfaces (numfaces-1 );
Device-> clear (0, 0, d3dclrear_target | d3dclear_zbuffer, 0 xffffffff, 1.0f, 0 );
Device-> beginscene ();
For (INT I = 0; I <mtrls. Size (); I ++)
{
Device-> setmaterial (& mtrls [I]);
Device-> settexture (0, textures [I]);
Pmesh-> drawsubset (I );
// Draw wireframe outline
Device-> setmaterial (& d3d: yellow_mtrl );
Device-> setrenderstate (d3drs_fillmode, d3dfill_wireframe );
Pmesh-> drawsubset (I );
Device-> setrenderstate (d3drs_fillmode, d3dfill_solid );
}
Device-> endscene ();
Device-> present (0, 0, 0, 0 );
}
Return true;
}
// When adding a patch, you sometimes need to add two patches to ensure that the reverse transformation of ECT can proceed smoothly.
Calculate the external body of a grid. The two common external bodies are external balls and external bodies. Other external bodies include the cylinder, elliptical body, Prism body, and capsule container.
An external ball or an external body is often used to accelerate Visibility Detection and collision. For example, if an external body or an external ball of a grid is invisible, the mesh is considered invisible.
The visibility of the external body is much lower than the visibility of each slice in the grid. For example, there is a transmitter in the scenario, to determine whether the emission will hit an object in the scene, because the object is composed of a triangle surface, you need to traverse each surface of each object, it also checks whether the emission (the mathematical model is Ray) will hit a certain surface. This method requires a lot of Ray/triangle intersection tests, in a scenario, each triangle surface of each object needs to be performed once. A more efficient way is to calculate the external body of each mesh (object, then, we will perform a ray/external body intersection test on each object. If the ray overlaps with the external body of an object, it is considered that the object is hit, which is a good approximation, if you want to improve the detection accuracy, you can use an external body to quickly exclude objects that are obviously not hit, and then use a more precise method to detect those objects that are most likely to be hit.
The d3dx Library provides functions to compute the external sphere and external body of a grid. These functions receive an array and then calculate the external body or external body based on these vertices.
Hresult winapi d3dxcomputeboundingsphere (
Const d3dxvector3 * pfirstposition,
DWORD numvertices,
DWORD dwstride,
D3dxvector3 * pcenter,
Float * pradius );
# Pfirstposition pointer to the position vector of the first vertex in the vertex array (each element of the array describes the corresponding vertex)
# Numvertices Number of vertices in the vertex Array
# The size of each vertex in dwstride, in bytes. This value is very important, because a vertex structure may contain a lot of attachment information not required by this function.
Such as normal vectors and texture coordinates, so that the function needs to know how many bytes should be skipped before finding the location of the next vertex.
# Pcenter return the ball Center Position of the external ball
# Pradius returns the radius of the external sphere
Hresult winapi d3dxcomputeboundingbox (
Const d3dxvector3 * pfirstposition,
DWORD numvertices,
DWORD dwstride,
D3dxvector3 * pmin, // returns the minimum point of the external body
D3dxvector3 * Pmax // returns the maximum point of the external body
);