本篇是
创建游戏内核(12)的续篇,其中涉及到的网格绘制知识请参阅D3D中网格模型的运用。
使用MESH加载网格
创建MESH类的目的是为了帮助程序员将那些小守护程序(demon)加载到一连串易于使用的类中,然后同其他将网格渲染到显示器上的对象结合起来使用。
点击下载源码和工程
首先定义一个结构体S_MESH来封装ID3DXMesh和ID3DXSkinInfo,以及材质、纹理、变换矩阵等;这个结构体被定位为链表结构。
struct S_MESH
{
public:
char* m_name; // name of mesh
ID3DXMesh* m_mesh; // mesh object
ID3DXMesh* m_skin_mesh; // skin mesh object
ID3DXSkinInfo* m_skin_info; // skin mesh information
DWORD m_num_materials; // number of materials in mesh
D3DMATERIAL9* m_materials; // array of materials
IDirect3DTexture9** m_textures; // array of textures
DWORD m_num_bones; // number of bones
D3DXMATRIX* m_matrices; // bone matrices
D3DXMATRIX** m_frame_matrices; // pointers to frame matrices
D3DXVECTOR3 m_min, m_max; // bounding box
float m_radius; // bounding sphere radius
S_MESH* m_next; // next mesh in list
//------------------------------------------------------------------------------------
// Constructor, initialize all member data.
//------------------------------------------------------------------------------------
S_MESH()
{
m_name = NULL;
m_mesh = NULL;
m_skin_mesh = NULL;
m_skin_info = NULL;
m_materials = NULL;
m_textures = NULL;
m_matrices = NULL;
m_frame_matrices = NULL;
m_next = NULL;
m_num_materials = 0;
m_num_bones = 0;
m_radius = 0.0f;
m_min.x = m_min.y = m_min.z = m_max.x = m_max.y = m_max.z = 0.0f;
}
//------------------------------------------------------------------------------------
// Destrcutor, release all resouce.
//------------------------------------------------------------------------------------
~S_MESH()
{
Release_COM(m_mesh);
Release_COM(m_skin_mesh);
Release_COM(m_skin_info);
delete[] m_name;
delete[] m_materials;
if(m_textures)
{
for(DWORD i = 0; i < m_num_materials; i++)
Release_COM(m_textures[i]);
delete[] m_textures;
}
delete[] m_matrices;
delete[] m_frame_matrices;
delete m_next;
}
//------------------------------------------------------------------------------------
// Find mesh object with specified name.
//------------------------------------------------------------------------------------
S_MESH* Find_Mesh(char* name)
{
// return first instance if name is NULL
if(name == NULL)
return this;
// compare names and return if exact match
if(m_name && !strcmp(name, m_name))
return this;
// search next in list
if(m_next != NULL)
{
S_MESH* mesh;
// recursively call
if((mesh = m_next->Find_Mesh(name)) != NULL)
return mesh;
}
return NULL;
}
//------------------------------------------------------------------------------------
// Get number of materials.
//------------------------------------------------------------------------------------
DWORD Get_Num_Materials()
{
return m_num_materials;
}
//------------------------------------------------------------------------------------
// Get material object.
//------------------------------------------------------------------------------------
D3DMATERIAL9* Get_Material(unsigned long index)
{
if(index >= m_num_materials || m_materials == NULL)
return NULL;
return &m_materials[index];
}
//------------------------------------------------------------------------------------
// Get texture object.
//------------------------------------------------------------------------------------
IDirect3DTexture9* Get_Texture(unsigned long index)
{
if(index >= m_num_materials || m_textures == NULL)
return NULL;
return m_textures[index];
}
//------------------------------------------------------------------------------------
// Copy all matrics from frames to local matrix array.
//------------------------------------------------------------------------------------
void Copy_Frame_To_Bone_Matrices()
{
if(m_num_bones != 0 && m_matrices && m_frame_matrices)
{
for(DWORD i = 0; i < m_num_bones; i++)
{
if(m_frame_matrices[i])
// gets the bone offset matrix and multiply it with frame transformed matrix
D3DXMatrixMultiply(&m_matrices[i], m_skin_info->GetBoneOffsetMatrix(i), m_frame_matrices[i]);
else
D3DXMatrixIdentity(&m_matrices[i]);
}
}
// process next in list (recursively call)
if(m_next != NULL)
m_next->Copy_Frame_To_Bone_Matrices();
}
};
接着定义一个结构体S_MESH_LIST来封装S_MESH,这个结构体也被定义为链表结构。
struct S_MESH_LIST
{
public:
S_MESH* m_mesh;
S_MESH_LIST* m_next;
S_MESH_LIST()
{
m_mesh = NULL;
m_next = NULL;
}
~S_MESH_LIST()
{
delete m_next;
}
};
再接着定义一个结构体S_FRAME表示框架层次,它也是链表结构,该结构体包含了S_MESH_LIST列表。
struct S_FRAME
{
public:
char* m_name;
S_MESH_LIST* m_mesh_list; // list of meshes attached to this frame
D3DXMATRIX m_mat_combined; // combined trasnformation matrix
D3DXMATRIX m_mat_transformed; // currently transformed matrix
D3DXMATRIX m_mat_original; // original .x File matrix
S_FRAME* m_parent; // parent frame
S_FRAME* m_child; // child frame
S_FRAME* m_sibling; // silbling frame
//------------------------------------------------------------------------------------
// Constructor, initialize member data.
//------------------------------------------------------------------------------------
S_FRAME()
{
m_name = NULL;
m_mesh_list = NULL;
D3DXMatrixIdentity(&m_mat_combined);
D3DXMatrixIdentity(&m_mat_transformed);
D3DXMatrixIdentity(&m_mat_original);
m_parent = m_sibling = m_child = NULL;
}
//------------------------------------------------------------------------------------
// Destructor, release all resource.
//------------------------------------------------------------------------------------
~S_FRAME()
{
delete m_name;
delete m_mesh_list;
delete m_child;
delete m_sibling;
}
//------------------------------------------------------------------------------------
// Find frame with specified name.
//------------------------------------------------------------------------------------
S_FRAME* Find_Frame(char* name)
{
// return this instances if name is NULL
if(name == NULL)
return this;
// compare names and return if exact match
if(m_name && !strcmp(name, m_name))
return this;
S_FRAME* frame;
// search child lists, recursively call.
if(m_child != NULL)
{
if((frame = m_child->Find_Frame(name)) != NULL)
return frame;
}
// search sibling lists, recursively call.
if(m_sibling != NULL)
{
if((frame = m_sibling->Find_Frame(name)) != NULL)
return frame;
}
return NULL;
}
//------------------------------------------------------------------------------------
// Reset transformed matrices to original matrices, recursively call.
//------------------------------------------------------------------------------------
void Reset_Matrices()
{
m_mat_transformed = m_mat_original;
if(m_child != NULL)
m_child->Reset_Matrices();
if(m_sibling != NULL)
m_sibling->Reset_Matrices();
}
//------------------------------------------------------------------------------------
// Add mesh into mesh list.
//------------------------------------------------------------------------------------
void Add_Mesh(S_MESH* mesh)
{
S_MESH_LIST* mesh_list = new S_MESH_LIST();
mesh_list->m_mesh = mesh;
mesh_list->m_next = m_mesh_list;
m_mesh_list = mesh_list;
}
};
在以上已经定义好的结构体基础上,我们定义一个类MESH来实现网格文件的加载。
class MESH
{
private:
GRAPHICS* _graphics;
long _num_meshes;
S_MESH* _meshes;
long _num_frames;
S_FRAME* _frames;
D3DXVECTOR3 _min, _max;
float _radius;
void _Parse_XFile_Data(ID3DXFileData* xfile_data, S_FRAME* parent_frame, char* texture_path);
void _Map_Frames_To_Bones(S_FRAME* frame);
public:
MESH();
~MESH();
BOOL Is_Loaded();
long Get_Num_Frames();
S_FRAME* Get_Parent_Frame();
S_FRAME* Get_Frame(char* name);
long Get_Num_Meshes();
S_MESH* Get_Parent_Mesh();
S_MESH* Get_Mesh(char* name);
void Get_Bounds(float* min_x, float* min_y, float* min_z, float* max_x, float* max_y, float* max_z, float* radius);
BOOL Load(GRAPHICS* graphics, char* filename, char* texture_path = ".\\");
void Free();
};
这是类MESH的实现:
//-------------------------------------------------------------------
// Constructor, initialize member data.
//-------------------------------------------------------------------
MESH::MESH()
{
_graphics = NULL;
_meshes = NULL;
_frames = NULL;
_num_meshes = 0;
_num_frames = 0;
_radius = 0.0f;
_min.x = _min.y = _min.z = _max.x = _max.y = _max.z = 0.0f;
}
//-------------------------------------------------------------------
// Destructor, release all resource.
//-------------------------------------------------------------------
MESH::~MESH()
{
Free();
}
//-------------------------------------------------------------------
// Release all resource.
//-------------------------------------------------------------------
void MESH::Free()
{
_graphics = NULL;
_num_meshes = 0;
delete _meshes; _meshes = NULL;
_num_frames = 0;
delete _frames; _frames = NULL;
_min.x = _min.y = _min.z = _max.x = _max.y = _max.z = 0.0f;
_radius = 0.0f;
}
//-------------------------------------------------------------------
// Load .x File from specified filename.
//-------------------------------------------------------------------
BOOL MESH::Load(GRAPHICS* graphics, char* filename, char* texture_path)
{
// free prior mesh object data
Free();
// error checking
if((_graphics = graphics) == NULL || filename == NULL)
return FALSE;
ID3DXFile* xfile = NULL;
// create the file object
if(FAILED(D3DXFileCreate(&xfile)))
return FALSE;
// register the templates
if(FAILED(xfile->RegisterTemplates((LPVOID) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
{
xfile->Release();
return FALSE;
}
ID3DXFileEnumObject* xfile_enum = NULL;
// create an enumeration object
if(FAILED(xfile->CreateEnumObject((LPVOID) filename, DXFILELOAD_FROMFILE, &xfile_enum)))
{
xfile->Release();
return FALSE;
}
// create a frame
S_FRAME* frame = new S_FRAME();
ID3DXFileData* xfile_data = NULL;
SIZE_T num_child;
// retrieve the number of children in this file data object
xfile_enum->GetChildren(&num_child);
// loop through all objects looking for the frames and meshes
for(SIZE_T i = 0; i < num_child; i++)
{
if(FAILED(xfile_enum->GetChild(i, &xfile_data)))
return FALSE;
// parse xfile data
_Parse_XFile_Data(xfile_data, frame, texture_path);
Release_COM(xfile_data);
}
// release used COM objects
Release_COM(xfile_enum);
Release_COM(xfile);
// see if we should keep the frame as root
if(frame->m_mesh_list != NULL)
{
_frames = frame;
_frames->m_name = new char[7];
strcpy(_frames->m_name, "%ROOT%");
}
else
{
// assign the root frame and release frame
_frames = frame->m_child;
S_FRAME* frame_ptr = _frames;
while(frame_ptr != NULL)
{
frame_ptr->m_parent = NULL;
frame_ptr = frame_ptr->m_sibling;
}
frame->m_child = NULL;
delete frame;
}
// map transformed matrix frames to bones
_Map_Frames_To_Bones(_frames);
S_MESH* mesh;
// calculate bounding box and sphere
if((mesh = _meshes) != NULL)
{
while(mesh != NULL)
{
_min.x = min(_min.x, mesh->m_min.x);
_min.y = min(_min.y, mesh->m_min.y);
_min.z = min(_min.z, mesh->m_min.z);
_max.x = min(_max.x, mesh->m_max.x);
_max.y = min(_max.y, mesh->m_max.y);
_max.z = min(_max.z, mesh->m_max.z);
_radius = max(_radius, mesh->m_radius);
mesh = mesh->m_next;
}
}
return TRUE;
}
//-------------------------------------------------------------------
// Parse specified xfile data, recursive function.
//-------------------------------------------------------------------
void MESH::_Parse_XFile_Data(ID3DXFileData* xfile_data, S_FRAME* parent_frame, char* texture_path)
{
// get the template type
GUID type;
// retrieve the globally unique identifier (GUID) of the object's template
if(FAILED(xfile_data->GetType(&type)))
return;
// get the template name (if any)
DWORD size;
if(FAILED(xfile_data->GetName(NULL, &size)))
return;
char* name = NULL;
if(size != 0)
{
if((name = new char[size]) != NULL)
xfile_data->GetName(name, &size);
}
// give template a default name if none found
if(name == NULL)
{
if((name = new char[9]) == NULL)
return;
strcpy(name, "$NoName$");
}
// set current frame
S_FRAME* current_frame = parent_frame;
// process the templates
if(type == TID_D3DRMFrame) // it's a frame
{
// create a new frame structure
S_FRAME* frame = new S_FRAME();
// store the name
frame->m_name = name;
name = NULL;
// add to parent frame
frame->m_parent = parent_frame;
frame->m_sibling = parent_frame->m_child;
parent_frame->m_child = frame;
// increase frame count
_num_frames++;
// set current frame with parent frame
current_frame = frame;
}
else if(type == TID_D3DRMFrameTransformMatrix) // it's a frame transformation matrix
{
D3DXMATRIX* frame_matrix = NULL;
// get frame transformation matrix
if(FAILED(xfile_data->Lock(&size, (LPCVOID*) &frame_matrix)))
return;
// set original matrix
parent_frame->m_mat_original = *frame_matrix;
xfile_data->Unlock();
}
else if(type == TID_D3DRMMesh) // it's a mesh
{
ID3DXBuffer* material_buffer = NULL;
ID3DXBuffer* adjacency = NULL;
S_MESH* mesh = NULL;
// see if mesh already loaded
if(_meshes == NULL || _meshes->Find_Mesh(name) == NULL)
{
// create a new mesh structure
mesh = new S_MESH();
// store the name
mesh->m_name = name;
name = NULL;
// load mesh data
if(FAILED(D3DXLoadSkinMeshFromXof(xfile_data, 0, _graphics->Get_Device_COM(),
&adjacency, &material_buffer, NULL, &mesh->m_num_materials, &mesh->m_skin_info, &mesh->m_mesh)))
{
delete[] name;
delete mesh;
return;
}
BYTE** ptr;
// calculate the bounding box and sphere
if(SUCCEEDED(mesh->m_mesh->LockVertexBuffer(D3DLOCK_READONLY, (void**) &ptr)))
{
// computes a coordinate-axis oriented bounding box
D3DXComputeBoundingBox((D3DXVECTOR3*) ptr, mesh->m_mesh->GetNumVertices(),
mesh->m_mesh->GetNumBytesPerVertex(), &mesh->m_min, &mesh->m_max);
// computes a bounding sphere for the mesh
D3DXComputeBoundingSphere((D3DXVECTOR3*) ptr, mesh->m_mesh->GetNumVertices(),
mesh->m_mesh->GetNumBytesPerVertex(), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &mesh->m_radius);
mesh->m_mesh->UnlockVertexBuffer();
}
// store number of bones (if any)
if(mesh->m_skin_info)
mesh->m_num_bones = mesh->m_skin_info->GetNumBones();
// create a matching skinned mesh if bone exist
if(mesh->m_skin_info != NULL && mesh->m_num_bones != 0)
{
// clones a mesh using a flexible vertex format (FVF) code
if(FAILED(mesh->m_mesh->CloneMeshFVF(0, mesh->m_mesh->GetFVF(), _graphics->Get_Device_COM(),
&mesh->m_skin_mesh)))
{
Release_COM(mesh->m_skin_info);
}
else // create an array of matrices to store bone transformations
{
// create the bone matrix array and clear it out
mesh->m_matrices = new D3DXMATRIX[mesh->m_num_bones];
for(DWORD i = 0; i < mesh->m_num_bones; i++)
D3DXMatrixIdentity(&mesh->m_matrices[i]);
// create the frame mapping matrix array and clear out
mesh->m_frame_matrices = new D3DXMATRIX*[mesh->m_num_bones];
for(DWORD i = 0; i < mesh->m_num_bones; i++)
mesh->m_frame_matrices[i] = NULL;
}
}
// load meterials or create a default one if none
if(mesh->m_num_materials == 0)
{
// create a default one
mesh->m_materials = new D3DMATERIAL9[1];
mesh->m_textures = new LPDIRECT3DTEXTURE9[1];
ZeroMemory(mesh->m_materials, sizeof(D3DMATERIAL9));
mesh->m_materials[0].Diffuse.r = 1.0f;
mesh->m_materials[0].Diffuse.g = 1.0f;
mesh->m_materials[0].Diffuse.b = 1.0f;
mesh->m_materials[0].Diffuse.a = 1.0f;
mesh->m_materials[0].Ambient = mesh->m_materials[0].Diffuse;
mesh->m_materials[0].Specular = mesh->m_materials[0].Diffuse;
mesh->m_textures[0] = NULL;
mesh->m_num_materials = 1;
}
else
{
// load the materials
D3DXMATERIAL* materials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();
mesh->m_materials = new D3DMATERIAL9[mesh->m_num_materials];
mesh->m_textures = new LPDIRECT3DTEXTURE9[mesh->m_num_materials];
char path[MAX_PATH];
for(DWORD i = 0; i < mesh->m_num_materials; i++)
{
mesh->m_materials[i] = materials[i].MatD3D;
mesh->m_materials[i].Ambient = mesh->m_materials[i].Diffuse;
// build a texture path and load it
sprintf(path, "%s%s", texture_path, materials[i].pTextureFilename);
if(FAILED(D3DXCreateTextureFromFile(_graphics->Get_Device_COM(), path, &mesh->m_textures[i])))
mesh->m_textures[i] = NULL;
}
}
Release_COM(material_buffer);
Release_COM(adjacency);
// link in mesh
mesh->m_next = _meshes;
_meshes = mesh;
_num_meshes++;
}
else
// Find mesh in list
mesh = _meshes->Find_Mesh(name);
// add mesh to frame
if(mesh != NULL)
parent_frame->Add_Mesh(mesh);
} // end if(type == TID_D3DRMMesh)
else if(type == TID_D3DRMAnimationSet || type == TID_D3DRMAnimation || type == TID_D3DRMAnimationKey)
{
// skip animation sets and animations
delete[] name;
return;
}
// release name buffer
delete[] name;
ID3DXFileData* child_xfile_data = NULL;
SIZE_T num_child;
xfile_data->GetChildren(&num_child);
// scan for embedded templates
for(SIZE_T i = 0; i < num_child; i++)
{
xfile_data->GetChild(i, &child_xfile_data);
// process embedded references
_Parse_XFile_Data(child_xfile_data, current_frame, texture_path);
Release_COM(child_xfile_data);
}
}
//-------------------------------------------------------------------
// Map frame transformation matrix to match bone, recursively call.
//-------------------------------------------------------------------
void MESH::_Map_Frames_To_Bones(S_FRAME *frame)
{
// return if no more frames to map
if(frame == NULL || frame->m_name == NULL)
return;
// scan through meshes looking for bone matches
S_MESH* mesh = _meshes;
while(mesh != NULL)
{
if(mesh->m_skin_info && mesh->m_num_bones && mesh->m_matrices && mesh->m_frame_matrices)
{
for(DWORD i = 0; i < mesh->m_num_bones; i++)
{
if(!strcmp(frame->m_name, mesh->m_skin_info->GetBoneName(i)))
{
mesh->m_frame_matrices[i] = &frame->m_mat_combined;
break;
}
}
}
mesh = mesh->m_next;
}
// scan through child frames
_Map_Frames_To_Bones(frame->m_child);
// scan throuogh sibling frames
_Map_Frames_To_Bones(frame->m_sibling);
}
//-------------------------------------------------------------------
// Judge whether the mesh has been loaded successfully.
//-------------------------------------------------------------------
BOOL MESH::Is_Loaded()
{
return (_meshes != NULL && _frames != NULL);
}
//-------------------------------------------------------------------
// Get number of frame.
//-------------------------------------------------------------------
long MESH::Get_Num_Frames()
{
return _num_frames;
}
//-------------------------------------------------------------------
// Get root frame.
//-------------------------------------------------------------------
S_FRAME* MESH::Get_Parent_Frame()
{
return _frames;
}
//-------------------------------------------------------------------
// Find frame with specified name.
//-------------------------------------------------------------------
S_FRAME* MESH::Get_Frame(char *name)
{
if(_frames == NULL)
return NULL;
return _frames->Find_Frame(name);
}
//-------------------------------------------------------------------
// Get number of mesh.
//-------------------------------------------------------------------
long MESH::Get_Num_Meshes()
{
return _num_meshes;
}
//-------------------------------------------------------------------
// Get root mesh.
//-------------------------------------------------------------------
S_MESH* MESH::Get_Mesh(char *name)
{
if(_meshes == NULL)
return NULL;
return _meshes->Find_Mesh(name);
}
//-------------------------------------------------------------------
// Get bound box coordiante and radius.
//-------------------------------------------------------------------
void MESH::Get_Bounds(float *min_x, float *min_y, float *min_z, float *max_x, float *max_y, float *max_z, float *radius)
{
if(min_x != NULL) *min_x = _min.x;
if(min_y != NULL) *min_y = _min.y;
if(min_z != NULL) *min_z = _min.z;
if(max_x != NULL) *max_x = _max.x;
if(max_y != NULL) *max_y = _max.y;
if(max_z != NULL) *max_z = _max.z;
if(radius != NULL) *radius = _radius;
}
接着我们编写一段测试代码来测试MESH类:
/*****************************************************************************
PURPOSE:
Test for class MESH.
*****************************************************************************/
#include "Core_Global.h"
#pragma warning(disable : 4996)
//===========================================================================
// Defines class APP which public inherits from class APPLICATION.
//===========================================================================
class APP : public APPLICATION
{
private:
GRAPHICS _graphics;
MESH _mesh;
BOOL _Draw_Mesh(S_FRAME* frame);
public:
BOOL Init();
BOOL Shutdown();
BOOL Frame();
};
//-----------------------------------------------------------------------------
// Initialize graphics, set display mode, set vertex buffer, load texture file.
//-----------------------------------------------------------------------------
BOOL APP::Init()
{
D3DXMATRIX mat_view;
// initialize graphics
if (! _graphics.Init())
return FALSE;
// set display mode for graphics
if(! _graphics.Set_Mode(Get_Hwnd(), TRUE, FALSE, 400, 400, 16))
return FALSE;
// disable D3D lighting
_graphics.Enable_Lighting(FALSE);
// set perspective projection transform matrix.
_graphics.Set_Perspective(D3DX_PI/4.0f, 1.33333f, 1.0f, 1000.0f);
// create and set the view matrix
D3DXMatrixLookAtLH(&mat_view,
&D3DXVECTOR3(0.0, 50.0, -150.0),
&D3DXVECTOR3(0.0, 50.0, 0.0),
&D3DXVECTOR3(0.0, 1.0, 0.0));
_graphics.Get_Device_COM()->SetTransform(D3DTS_VIEW, &mat_view);
// load mesh
if(! _mesh.Load(&_graphics, "warrior.x"))
return FALSE;
return TRUE;
}
//-----------------------------------------------------------------------------
// Release all d3d resource.
//-----------------------------------------------------------------------------
BOOL APP::Shutdown()
{
return TRUE;
}
//-----------------------------------------------------------------------------
// Render a frame.
//-----------------------------------------------------------------------------
BOOL APP::Frame()
{
D3DXMATRIX mat_world;
// clear display with specified color
_graphics.Clear_Display(D3DCOLOR_RGBA(0, 0, 0, 255));
// begin scene
if(_graphics.Begin_Scene())
{
// create and set the world transformation matrix
// rotate object along z-axis
D3DXMatrixRotationY(&mat_world, (float) (timeGetTime() / 1000.0));
_graphics.Get_Device_COM()->SetTransform(D3DTS_WORLD, &mat_world);
// get root frame
S_FRAME* root_frame = _mesh.Get_Parent_Frame();
// draw mesh
_Draw_Mesh(root_frame);
// end the scene
_graphics.End_Scene();
}
// display video buffer
_graphics.Display();
return TRUE;
}
//-----------------------------------------------------------------------------
// Draw mesh, call recursively.
//-----------------------------------------------------------------------------
BOOL APP::_Draw_Mesh(S_FRAME* frame)
{
D3DXMATRIX* matrices = NULL;
ID3DXMesh* mesh_to_draw;
S_MESH* mesh;
// return if no frame
if(frame == NULL)
return FALSE;
if(frame->m_mesh_list != NULL)
{
// draw meshes if any in frame
if((mesh = frame->m_mesh_list->m_mesh) != NULL)
{
// setup pointer to mesh to draw
mesh_to_draw = mesh->m_mesh;
// generate mesh from skinned mesh to draw with
if(mesh->m_skin_mesh != NULL && mesh->m_skin_info != NULL)
{
DWORD num_bones = mesh->m_skin_info->GetNumBones();
// allocate an array of matrices to orient bones
matrices = new D3DXMATRIX[num_bones];
// set all bones orientation to identity
for(DWORD i = 0; i < num_bones; i++)
D3DXMatrixIdentity(&matrices[i]);
// lock source and destination vertex buffers
void* source = NULL;
void* dest = NULL;
// locks a vertex buffer and obtains a pointer to the vertex buffer memory
mesh->m_mesh->LockVertexBuffer(0, &source);
mesh->m_skin_mesh->LockVertexBuffer(0, &dest);
// Update skinned mesh, applies software skinning to the target vertices based on the current matrices.
mesh->m_skin_info->UpdateSkinnedMesh(matrices, NULL, source, dest);
// unlock buffers
mesh->m_mesh->UnlockVertexBuffer();
mesh->m_skin_mesh->UnlockVertexBuffer();
// pointer to skin mesh to draw
mesh_to_draw = mesh->m_skin_mesh;
}
// render the mesh
for(DWORD i = 0; i < mesh->Get_Num_Materials(); i++)
{
// set the materials properties for the device
_graphics.Get_Device_COM()->SetMaterial(&mesh->m_materials[i]);
// assign a texture to a stage for a device
_graphics.Get_Device_COM()->SetTexture(0, mesh->m_textures[i]);
// draw a subset of a mesh
mesh_to_draw->DrawSubset(i);
}
// free array of matrices
delete[] matrices;
matrices = NULL;
}
}
// draw child frames, recursively call.
_Draw_Mesh(frame->m_child);
return TRUE;
}
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
APP app;
return app.Run();
}
运行截图: