D3D中的网格模型(3)
10.7 复制
有时我们需要将一个mesh中的数据拷贝到另一个mesh中,这时可以使用ID3DXBaseMesh::CloneMeshFVF方法。
HRESULT ID3DXMesh::CloneMeshFVF( DWORD Options, DWORD FVF, LPDIRECT3DDEVICE9 pDevice, LPD3DXMESH* ppCloneMesh ); |
Options — 用来创建mesh的一个或多个创建标志。要了解所有标志信息请查看sdk文档。现在列出一部分:
D3DXMESH_32BIT — mesh使用32位索引。
D3DXMESH_MANAGED — mesh数据将被放在托管的内存中。
D3DXMESH_WRITEONLY — mesh数据只能执行写操作,不能执行读操作。
D3DXMESH_DYNAMIC — mesh缓存将是动态的。
FVF — 创建复制mesh的灵活顶点格式。
pDevice — 与复制mesh有关的设备。
ppCloneMesh — 输出复制的mesh。
注意这个方法允许指定与原mesh不同的options和FVF。例如我们有顶点格式为D3DFVF_XYZ的mesh,现在想复制一个顶点格式为 D3DFVF_XYZ|D3DFVF_NORMAL的mesh。我们可以这样写:
// 假设_mesh和device是有效的 ID3DXMesh* clone = 0; Mesh->CloneMeshFVF( Mesh->GetOptions(), // 使用与源模型同样的选项 D3DFVF_XYZ | D3DFVF_NORMAL,// 指定克隆的FVF Device, &clone ); |
10.8 创建一个Mesh(D3DXCreateMeshFVF)
我们可以使用D3DXCreate*函数来创建mesh物体。然而,我们也可以使用D3DXCreateMeshFVF函数来创建一个空mesh。所谓空 mesh是指我们已经指定了顶点数和面数,函数D3DXCreateMeshFVF也分配了适当大小的内存给顶点、顶点索引、属性缓冲区。有了这些缓冲区后,就可以手动填写上下文数据了(需要分别向顶点缓存,索引缓存、属性缓存提供顶点、索引、属性数据)。
我们使用D3DXCreateMeshFVF函数来创建空mesh:
HRESULT D3DXCreateMeshFVF( DWORD NumFaces, DWORD NumVertices, DWORD Options, DWORD FVF, LPDIRECT3DDEVICE9 pDevice, LPD3DXMESH* ppMesh ); |
NumFaces — mesh将拥有的面数。该值必须大于0。
NumVertices — mesh将拥有的顶点数。该值必须大于0。
Options —用来创建mesh的一个或多个创建标志。要了解所有标志信息请查看sdk文档,现在列出一部分:
D3DXMESH_32BIT — mesh使用32位索引。
D3DXMESH_MANAGED — mesh数据将被放在托管的内存中。
D3DXMESH_WRITEONLY — mesh数据只能执行写操作,不能执行读操作。
D3DXMESH_DYNAMIC — mesh缓存将是动态的。
FVF — mesh的顶点格式。
pDevice — 与mesh相关的设备。
ppMesh — 输出创建好的mesh。
另外,你也可以使用D3DXCreateMesh来创建空mesh。它的原型是:
HRESULT D3DXCreateMesh( DWORD NumFaces, DWORD NumVertices, DWORD Options, CONST LPD3DVERTEXELEMENT9* pDeclaration, LPDIRECT3DDEVICE9 pDevice, LPD3DXMESH* ppMesh ); |
这些参数和D3DXCreateMeshFVF的参数是非常相似的,除了第四个。作为替代指定的FVF,我们指定一个D3DVERTEXELEMENT9 结构,它描述了顶点格式。
HRESULT D3DXDeclaratorFromFVF( DWORD FVF, // input format D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE]//output format ); |
这个函数通过输入一个FVF返回一个D3DVERTEXELEMENT9结构的数组。注意MAX_FVF_DECL_SIZE的定义如下:< /p>
typedef enum { MAX_FVF_DECL_SIZE = 18 } MAX_FVF_DECL_SIZE; |
10.9 实例程序:创建和渲染Mesh
该实例程序是渲染一个立方体(如图10.5):
它演示了这一章中的大部分功能,包括如下一些操作:
创建一个空mesh。
用一个立方体几何信息来填充mesh。
根据mesh的每个面指定子集。
产生mesh的邻接信息。
优化mesh。
绘制mesh。
Demonstrates how to create an empty ID3DXMesh object with D3DXCreateMeshFVF,
how to fill the vertex, index, and attribute buffers, how to optimize a mesh
and gnerate an attribute table, and how to render it.
************************************************************************************* */
#include < fstream >
#include < vector >
#include " d3dUtility.h "
#pragma warning(disable : 4100 )
using namespace std;
class cTextureVertex
{
public :
float m_x, m_y, m_z;
float m_nx, m_ny, m_nz;
float m_u, m_v;
cTextureVertex() { }
cTextureVertex( float x, float y, float z,
float nx, float ny, float nz,
float u, float v)
{
m_x = x; m_y = y; m_z = z;
m_nx = nx; m_ny = ny; m_nz = nz;
m_u = u; m_v = v;
}
};
const DWORD TEXTURE_VERTEX_FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
/////////////////////////////////////////////////////////////////////////////////////////////////// /
const int WIDTH = 640 ;
const int HEIGHT = 480 ;
IDirect3DDevice9 * g_d3d_device;
ID3DXMesh * g_d3d_mesh;
IDirect3DTexture9 * g_d3d_textures[ 3 ]; // texture for each subset
const DWORD g_num_subsets = 3 ;
ofstream g_out_file; // used to dump mesh data to file
void dump_vertices(ofstream & outFile, ID3DXMesh * mesh);
void dump_indices(ofstream & outFile, ID3DXMesh * mesh);
void dump_attribute_buffer(ofstream & outFile, ID3DXMesh * mesh);
void dump_adjacency_buffer(ofstream & outFile, ID3DXMesh * mesh);
void dump_attribute_table(ofstream & outFile, ID3DXMesh * mesh);
/////////////////////////////////////////////////////////////////////////////////////////////////// /
bool setup()
{
// We are going to fill the empty mesh with the geometry of a box,
// so we need 12 triangles and 24 vertices.
if (FAILED(D3DXCreateMeshFVF( 12 , 24 , D3DXMESH_MANAGED, TEXTURE_VERTEX_FVF, g_d3d_device, & g_d3d_mesh)))
{
MessageBox(NULL, " D3DXCreateMeshFVF() - FAILED " , " ERROR " , MB_OK);
return false ;
}
// fill in vertices of a box
cTextureVertex * v;
g_d3d_mesh -> LockVertexBuffer( 0 , ( void ** ) & v);
// fill in the front face vertex data
v[ 0 ] = cTextureVertex( - 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 0.0f , 0.0f );
v[ 1 ] = cTextureVertex( - 1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 0.0f , 1.0f );
v[ 2 ] = cTextureVertex( 1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 1.0f , 1.0f );
v[ 3 ] = cTextureVertex( 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , - 1.0f , 1.0f , 0.0f );
// fill in the back face vertex data
v[ 4 ] = cTextureVertex( - 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 0.0f , 0.0f );
v[ 5 ] = cTextureVertex( 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 0.0f , 1.0f );
v[ 6 ] = cTextureVertex( 1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 1.0f , 1.0f );
v[ 7 ] = cTextureVertex( - 1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 1.0f , 0.0f );
// fill in the top face vertex data
v[ 8 ] = cTextureVertex( - 1.0f , 1.0f , - 1.0f , 0.0f , 1.0f , 0.0f , 0.0f , 0.0f );
v[ 9 ] = cTextureVertex( - 1.0f , 1.0f , 1.0f , 0.0f , 1.0f , 0.0f , 0.0f , 1.0f );
v[ 10 ] = cTextureVertex( 1.0f , 1.0f , 1.0f , 0.0f , 1.0f , 0.0f , 1.0f , 1.0f );
v[ 11 ] = cTextureVertex( 1.0f , 1.0f , - 1.0f , 0.0f , 1.0f , 0.0f , 1.0f , 0.0f );
// fill in the bottom face vertex data
v[ 12 ] = cTextureVertex( - 1.0f , - 1.0f , - 1.0f , 0.0f , - 1.0f , 0.0f , 0.0f , 0.0f );
v[ 13 ] = cTextureVertex( 1.0f , - 1.0f , - 1.0f , 0.0f , - 1.0f , 0.0f , 0.0f , 1.0f );
v[ 14 ] = cTextureVertex( 1.0f , - 1.0f , 1.0f , 0.0f , - 1.0f , 0.0f , 1.0f , 1.0f );
v[ 15 ] = cTextureVertex( - 1.0f , - 1.0f , 1.0f , 0.0f , - 1.0f , 0.0f , 1.0f , 0.0f );
// fill in the left face vertex data
v[ 16 ] = cTextureVertex( - 1.0f , - 1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f , 0.0f );
v[ 17 ] = cTextureVertex( - 1.0f , 1.0f , 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f , 1.0f );
v[ 18 ] = cTextureVertex( - 1.0f , 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , 1.0f , 1.0f );
v[ 19 ] = cTextureVertex( - 1.0f , - 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , 1.0f , 0.0f );
// fill in the right face vertex data
v[ 20 ] = cTextureVertex( 1.0f , - 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 0.0f , 0.0f );
v[ 21 ] = cTextureVertex( 1.0f , 1.0f , - 1.0f , 1.0f , 0.0f , 0.0f , 0.0f , 1.0f );
v[ 22 ] = cTextureVertex( 1.0f , 1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 1.0f );
v[ 23 ] = cTextureVertex( 1.0f , - 1.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , 0.0f );
g_d3d_mesh -> UnlockVertexBuffer();
// define the triangles of the box
WORD * index;
g_d3d_mesh -> LockIndexBuffer( 0 , ( void ** ) & index);
// fill in the front face index data
index[ 0 ] = 0 ; index[ 1 ] = 1 ; index[ 2 ] = 2 ;
index[ 3 ] = 0 ; index[ 4 ] = 2 ; index[ 5 ] = 3 ;
// fill in the back face index data
index[ 6 ] = 4 ; index[ 7 ] = 5 ; index[ 8 ] = 6 ;
index[ 9 ] = 4 ; index[ 10 ] = 6 ; index[ 11 ] = 7 ;
// fill in the top face index data
index[ 12 ] = 8 ; index[ 13 ] = 9 ; index[ 14 ] = 10 ;
index[ 15 ] = 8 ; index[ 16 ] = 10 ; index[ 17 ] = 11 ;
// fill in the bottom face index data
index[ 18 ] = 12 ; index[ 19 ] = 13 ; index[ 20 ] = 14 ;
index[ 21 ] = 12 ; index[ 22 ] = 14 ; index[ 23 ] = 15 ;
// fill in the left face index data
index[ 24 ] = 16 ; index[ 25 ] = 17 ; index[ 26 ] = 18 ;
index[ 27 ] = 16 ; index[ 28 ] = 18 ; index[ 29 ] = 19 ;
// fill in the right face index data
index[ 30 ] = 20 ; index[ 31 ] = 21 ; index[ 32 ] = 22 ;
index[ 33 ] = 20 ; index[ 34 ] = 22 ; index[ 35 ] = 23 ;
g_d3d_mesh -> UnlockIndexBuffer();
// Specify the subset each triangle belongs to, in this example we will use three subsets,
// the first two faces of the cube specified will be in subset 0, the next two faces will
// be in subset 1 and the the last two faces will be in subset 2.
DWORD * attr_buffer;
g_d3d_mesh -> LockAttributeBuffer( 0 , & attr_buffer);
for ( int i = 0 ; i < 4 ; i ++ )
attr_buffer[i] = 0 ;
for ( int i = 4 ; i < 8 ; i ++ )
attr_buffer[i] = 1 ;
for ( int i = 8 ; i < 12 ; i ++ )
attr_buffer[i] = 2 ;
g_d3d_mesh -> UnlockAttributeBuffer();
// optimize the mesh to generate an attribute table
vector < DWORD > adjacency_buffer(g_d3d_mesh -> GetNumFaces() * 3 );
g_d3d_mesh -> GenerateAdjacency( 0.0f , & adjacency_buffer[ 0 ]);
g_d3d_mesh -> OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE,
& adjacency_buffer[ 0 ], NULL, NULL, NULL);
// dump the mesh data to file
g_out_file.open( " Mesh Dump.txt " );
dump_vertices(g_out_file, g_d3d_mesh);
dump_indices(g_out_file, g_d3d_mesh);
dump_attribute_table(g_out_file, g_d3d_mesh);
dump_attribute_buffer(g_out_file, g_d3d_mesh);
dump_adjacency_buffer(g_out_file, g_d3d_mesh);
g_out_file.close();
// create the texture and set filters
D3DXCreateTextureFromFile(g_d3d_device, " brick0.jpg " , & g_d3d_textures[ 0 ]);
D3DXCreateTextureFromFile(g_d3d_device, " brick1.jpg " , & g_d3d_textures[ 1 ]);
D3DXCreateTextureFromFile(g_d3d_device, " checker.jpg " , & g_d3d_textures[ 2 ]);
g_d3d_device -> SetSamplerState( 0 , D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_d3d_device -> SetSamplerState( 0 , D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_d3d_device -> SetSamplerState( 0 , D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
// disable lighting
g_d3d_device -> SetRenderState(D3DRS_LIGHTING, FALSE);
// set camera
D3DXVECTOR3 pos( 0.0f , 0 .f, - 4.0f );
D3DXVECTOR3 target( 0.0f , 0.0f , 0.0f );
D3DXVECTOR3 up( 0.0f , 1.0f , 0.0f );
D3DXMATRIX view_matrix;
D3DXMatrixLookAtLH( & view_matrix, & pos, & target, & up);
g_d3d_device -> SetTransform(D3DTS_VIEW, & view_matrix);
// set the projection matrix
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH( & proj, D3DX_PI * 0.5f , ( float )WIDTH / HEIGHT, 1.0f , 1000.0f );
g_d3d_device -> SetTransform(D3DTS_PROJECTION, & proj);
return true ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
void cleanup()
{
safe_release < ID3DXMesh *> (g_d3d_mesh);
safe_release < IDirect3DTexture9 *> (g_d3d_textures[ 0 ]);
safe_release < IDirect3DTexture9 *> (g_d3d_textures[ 1 ]);
safe_release < IDirect3DTexture9 *> (g_d3d_textures[ 2 ]);
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
bool display( float time_delta)
{
// update: rotate the cube
static float y = 0.0f ;
D3DXMATRIX x_rot_matrix, y_rot_matrix;
D3DXMatrixRotationX( & x_rot_matrix, D3DX_PI * 0.2f );
D3DXMatrixRotationY( & y_rot_matrix, y);
D3DXMATRIX world_matrix = x_rot_matrix * y_rot_matrix;
g_d3d_device -> SetTransform(D3DTS_WORLD, & world_matrix);
y += time_delta;
if (y >= 6.28f )
y = 0.0f ;
// render now
g_d3d_device -> Clear( 0 , NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000 , 1.0f , 0 );
g_d3d_device -> BeginScene();
for ( int i = 0 ; i < g_num_subsets; i ++ )
{
g_d3d_device -> SetTexture( 0 , g_d3d_textures[i]);
g_d3d_mesh -> DrawSubset(i);
}
g_d3d_device -> EndScene();
g_d3d_device -> Present(NULL, NULL, NULL, NULL);
return true ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage( 0 );
break ;
case WM_KEYDOWN:
if (word_param == VK_ESCAPE)
DestroyWindow(hwnd);
break ;
}
return DefWindowProc(hwnd, msg, word_param, long_param);
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
{
if ( ! init_d3d(inst, WIDTH, HEIGHT, true , D3DDEVTYPE_HAL, & g_d3d_device))
{
MessageBox(NULL, " init_d3d() - failed. " , 0 , MB_OK);
return 0 ;
}
if ( ! setup())
{
MessageBox(NULL, " Steup() - failed. " , 0 , MB_OK);
return 0 ;
}
enter_msg_loop(display);
cleanup();
g_d3d_device -> Release();
return 0 ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
void dump_vertices(ofstream & out_file, ID3DXMesh * mesh)
{
out_file << " Vertices: " << endl;
out_file << " --------- " << endl;
cTextureVertex * v;
mesh -> LockVertexBuffer( 0 , ( void ** ) & v);
for (unsigned int i = 0 ; i < mesh -> GetNumVertices(); i ++ )
{
out_file << " Vertex " << i << " :( " ;
out_file << v[i].m_x << " , " << v[i].m_y << " , " << v[i].m_z << " , " ;
out_file << v[i].m_nx << " , " << v[i].m_ny << " , " << v[i].m_nz << " , " ;
out_file << v[i].m_u << " , " << v[i].m_v << " ) " << endl;
}
mesh -> UnlockVertexBuffer();
out_file << endl << endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
void dump_indices(ofstream & out_file, ID3DXMesh * mesh)
{
out_file << " Indices: " << endl;
out_file << " -------- " << endl << endl;
WORD * indices;
mesh -> LockIndexBuffer( 0 , ( void ** ) & indices);
for (unsigned int i = 0 ; i < mesh -> GetNumFaces(); i ++ )
{
out_file << " Triangle " << i << " : " ;
out_file << indices[i * 3 ] << " " << indices[i * 3 + 1 ] << " " << indices[i * 3 + 2 ] << endl;
}
mesh -> UnlockIndexBuffer();
out_file << endl << endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
void dump_attribute_buffer(ofstream & out_file, ID3DXMesh * mesh)
{
out_file << " Attribute Buffer: " << endl;
out_file << " ----------------- " << endl << endl;
DWORD * attr_buffer;
mesh -> LockAttributeBuffer( 0 , & attr_buffer);
// an attribute for each face
for (unsigned int i = 0 ; i < mesh -> GetNumFaces(); i ++ )
out_file << " Triangle " << i << " lives in subset " << attr_buffer[i] << endl;
mesh -> UnlockAttributeBuffer();
out_file << endl << endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
void dump_adjacency_buffer(ofstream & out_file, ID3DXMesh * mesh)
{
out_file << " Adjacency Buffer: " << endl;
out_file << " ----------------- " << endl << endl;
// three entries per face
vector < DWORD > adjacency_buffer(mesh -> GetNumFaces() * 3 );
mesh -> GenerateAdjacency( 0.0f , & adjacency_buffer[ 0 ]);
for (unsigned int i = 0 ; i < mesh -> GetNumFaces(); i ++ )
{
out_file << " Triangle's adjacent to triangle " << i << " : " ;
out_file << adjacency_buffer[i * 3 ] << " "
<< adjacency_buffer[i * 3 + 1 ] << " "
<< adjacency_buffer[i * 3 + 2 ] << endl;
}
out_file << endl << endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
void dump_attribute_table(ofstream & out_file, ID3DXMesh * mesh)
{
out_file << " Attribute Table: " << endl;
out_file << " ---------------- " << endl << endl;
DWORD num_entries; // number of entries in the attribute table
mesh -> GetAttributeTable( 0 , & num_entries);
vector < D3DXATTRIBUTERANGE > table(num_entries);
mesh -> GetAttributeTable( & table[ 0 ], & num_entries);
for (unsigned int i = 0 ; i < num_entries; i ++ )
{
out_file << " Entry " << i << endl;
out_file << " ----------- " << endl;
out_file << " Subset ID: " << table[i].AttribId << endl;
out_file << " Face Start: " << table[i].FaceStart << endl;
out_file << " Face Count: " << table[i].FaceCount << endl;
out_file << " Vertex Start: " << table[i].VertexStart << endl;
out_file << " Vertex Count: " << table[i].VertexCount << endl;
out_file << endl;
}
out_file << endl << endl;
}
下载源程序