|
|
发表于 2009-2-27 17:08:00
|
显示全部楼层
Re:请教达人~~~关于骨骼动画的问题。
//cMesh------------------------------------------------------------------------------------------------------------------
cMesh::cMesh()
{
m_Graphics = NULL;
m_NumMeshes = 0;
m_Meshes = NULL;
m_NumFrames = 0;
m_Frames = NULL;
m_Min.x = m_Min.y = m_Min.z = m_Max.x = m_Max.y = m_Max.z = 0.0f;
m_Radius = 0.0f;
}
cMesh::~cMesh()
{
Free();
}
BOOL cMesh::IsLoaded()
{
if(m_Meshes != NULL && m_Frames != NULL)
return TRUE;
return FALSE;
}
HRESULT cMesh: oad(cGraphics *Graphics,char *Filename, char *TexturePath)
{
ID3DXFile *pDXFile = NULL;
ID3DXFileEnumObject *pDXEnum = NULL;
ID3DXFileData *pDXData = NULL;
sFrame *TempFrame, *FramePtr;
sMesh *Mesh;
DWORD dsize;
// Free prior mesh object data
Free();
// Error checking
if((m_Graphics = Graphics) == NULL || Filename == NULL)
return E_FAIL;
// Create the file object
if(FAILED(D3DXFileCreate(&pDXFile)))
return E_FAIL;
// Register the templates
if(FAILED(pDXFile->RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
{
pDXFile->Release();
return E_FAIL;
}
// Create an enumeration object
if(FAILED(pDXFile->CreateEnumObject((LPVOID)Filename, DXFILELOAD_FROMFILE, &pDXEnum)))
{
pDXFile->Release();
return E_FAIL;
}
// Create a temporary frame
TempFrame = new sFrame();
// Loop through all objects looking for the frames and meshes
if(SUCCEEDED(pDXEnum->GetChildren(&dsize)))
{
for(DWORD i=0;i<dsize;i++)
{
pDXEnum->GetChild(i,&pDXData);
ParseXFileData(pDXData, TempFrame,TexturePath);
ReleaseCOM(pDXData);
}
}
// See if we should keep the tempframe as root
if(TempFrame->MeshList != NULL)
{
m_Frames = TempFrame;
m_Frames->Name = new char[7];
strcpy(m_Frames->Name, "%ROOT%");
}
else
{
// Assign the root frame and release temporary frame
m_Frames = TempFrame->Child;
FramePtr = m_Frames;
while(FramePtr != NULL)
{
FramePtr-> arent = NULL;
FramePtr = FramePtr->Sibling;
}
TempFrame->Child = NULL;
delete TempFrame;
}
// Match frames to bones (for matrices)
MapFramesToBones(m_Frames);
// Calculate bounding box and sphere
if((Mesh = m_Meshes) != NULL)
{
while(Mesh != NULL)
{
m_Min.x = min(m_Min.x, Mesh->m_Min.x);
m_Min.y = min(m_Min.y, Mesh->m_Min.y);
m_Min.z = min(m_Min.z, Mesh->m_Min.z);
m_Max.x = max(m_Max.x, Mesh->m_Max.x);
m_Max.y = max(m_Max.y, Mesh->m_Max.y);
m_Max.z = max(m_Max.z, Mesh->m_Max.z);
m_Radius = max(m_Radius, Mesh->m_Radius);
Mesh = Mesh->m_Next;
}
}
return S_OK;
}
void cMesh: arseXFileData(ID3DXFileData *pDataObj,sFrame *ParentFrame,char *TexturePath)
{
ID3DXFileData *pSubObj = NULL;
GUID Type;
char *Name = NULL;
DWORD Size;
sFrame *SubFrame = NULL;
char Path[MAX_PATH];
sFrame *Frame = NULL;
D3DXMATRIX *FrameMatrix = NULL;
sMesh *Mesh = NULL;
ID3DXBuffer *MaterialBuffer = NULL;
D3DXMATERIAL *Materials = NULL;
ID3DXBuffer *Adjacency = NULL;
DWORD *AdjacencyIn = NULL;
DWORD *AdjacencyOut = NULL;
DWORD i;
DWORD dSize;
BYTE **Ptr;
LPCVOID Buffer;
D3DXMATRIX Matrix;
if(FAILED(pDataObj->GetType(&Type)))
{
return;
}
// Get the template name (if any)
if(FAILED(pDataObj->GetName(NULL, &Size)))
return;
if(Size)
{
if((Name = new char[Size]) != NULL)
pDataObj->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 sub frame
SubFrame = ParentFrame;
// Process the templates
// Frame
if(Type == TID_D3DRMFrame)
{
// Create a new frame structure
Frame = new sFrame();
// Store the name
Frame->Name = Name;
Name = NULL;
// Add to parent frame
Frame->Parent = ParentFrame;
Frame->Sibling = ParentFrame->Child;
ParentFrame->Child = Frame;
// Increase frame count
m_NumFrames++;
// Set sub frame parent
SubFrame = Frame;
}
if(Type == TID_D3DRMFrameTransformMatrix&&pDataObj)
{
dSize = 0;
Buffer = NULL;
if(FAILED(pDataObj->Lock( &dSize, &Buffer )))
return ;
if( dSize == sizeof( D3DXMATRIX ) )
{
memcpy( &SubFrame->TransformationMatrix, Buffer, dSize );
pDataObj->Unlock();
SubFrame->matOriginal = SubFrame->TransformationMatrix;
}
}
if(Type == TID_D3DRMMesh)
{// See if mesh already loaded
if(m_Meshes == NULL || m_Meshes->FindMesh(Name) == NULL)
{// Create a new mesh structure
Mesh = new sMesh();
// Store the name
Mesh->m_Name = Name;
Name = NULL;
// Load mesh data
if(FAILED(D3DXLoadSkinMeshFromXof(pDataObj, 0,
m_Graphics->GetDevice(),
&Adjacency,
&MaterialBuffer, NULL, &Mesh->m_NumMaterials,
&Mesh->m_SkinInfo,
&Mesh->m_Mesh)))
{
delete Mesh;
return;
}
// Calculate the bounding box and sphere
if(SUCCEEDED(Mesh->m_Mesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&Ptr)))
{
D3DXComputeBoundingBox((D3DXVECTOR3*)Ptr, Mesh->m_Mesh->GetNumVertices(),
Mesh->m_Mesh->GetNumBytesPerVertex(), &Mesh->m_Min, &Mesh->m_Max);
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 # of bones (if any)
if(Mesh->m_SkinInfo)
Mesh->m_NumBones = Mesh->m_SkinInfo->GetNumBones();
// Create a matching skinned mesh if bone exist
if(Mesh->m_SkinInfo != NULL && Mesh->m_NumBones != 0)
{
if(FAILED(Mesh->m_Mesh->CloneMeshFVF(0, Mesh->m_Mesh->GetFVF(),
m_Graphics->GetDevice(), &Mesh->m_SkinMesh)))
ReleaseCOM(Mesh->m_SkinInfo);
}
// Create an array of matrices to store bone transformations
if(Mesh->m_SkinInfo != NULL && Mesh->m_NumBones != 0)
{
// Create the bone matrix array and clear it out
Mesh->m_Matrices = new D3DXMATRIX[Mesh->m_NumBones];
for(i=0;i<Mesh->m_NumBones;i++)
{
D3DXMatrixIdentity(&Mesh->m_Matrices);
}
// Create the frame mapping matrix array and clear out
Mesh->m_FrameMatrices = new D3DXMATRIX*[Mesh->m_NumBones];
for(i=0;i<Mesh->m_NumBones;i++)
{
Mesh->m_FrameMatrices = NULL;
}
}
// Load materials or create a default one if none
if(!Mesh->m_NumMaterials)
{// 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_NumMaterials = 1;
}
else
{// Load the materials
Materials = (D3DXMATERIAL*)MaterialBuffer->GetBufferPointer();
Mesh->m_Materials = new D3DMATERIAL9[Mesh->m_NumMaterials];
Mesh->m_Textures = new LPDIRECT3DTEXTURE9[Mesh->m_NumMaterials];
for(i=0;i<Mesh->m_NumMaterials;i++)
{
Mesh->m_Materials = Materials.MatD3D;
Mesh->m_Materials.Ambient = Mesh->m_Materials.Diffuse;
// Build a texture path and load it
sprintf(Path, "%s%s", TexturePath, Materials.pTextureFilename);
if(FAILED(D3DXCreateTextureFromFile(m_Graphics->GetDevice(),
Path,
&Mesh->m_Textures)))
{
Mesh->m_Textures = NULL;
}
}
}
ReleaseCOM(MaterialBuffer);
// link in mesh
Mesh->m_Next = m_Meshes;
m_Meshes = Mesh;
m_NumMeshes++;
}
else
{// Find mesh in list
Mesh = m_Meshes->FindMesh(Name);
}
// Add mesh to frame
if(Mesh != NULL)
ParentFrame->AddMesh(Mesh);
}
if(Type == TID_D3DRMAnimationSet || Type == TID_D3DRMAnimation || Type == TID_D3DRMAnimationKey)
{
delete [] Name;
return;
}
// Release name buffer
delete [] Name;
dSize=0;
if(SUCCEEDED(pDataObj->GetChildren(&dSize))&&pDataObj)
{
for(i=0;i<dSize;i++)
{
pDataObj->GetChild(i,&pSubObj);
if(!pSubObj->IsReference())
{
ParseXFileData(pSubObj, SubFrame,TexturePath);
ReleaseCOM(pSubObj);
}
}
}
}
void cMesh::MapFramesToBones(sFrame *Frame)
{
sMesh *Mesh;
DWORD i;
// Return if no more frames to map
if(Frame == NULL || Frame->Name == NULL)
return;
// Scan through meshes looking for bone matches
Mesh = m_Meshes;
while(Mesh != NULL)
{
if(Mesh->m_SkinInfo && Mesh->m_NumBones && Mesh->m_Matrices != NULL && Mesh->m_FrameMatrices != NULL)
{
for(i=0;i<Mesh->m_NumBones;i++)
{
if(!strcmp(Frame->Name, Mesh->m_SkinInfo->GetBoneName(i)))
{
Mesh->m_FrameMatrices = &Frame->matCombined;
break;
}
}
}
Mesh = Mesh->m_Next;
}
// Scan through child frames
MapFramesToBones(Frame->Child);
// Scan through sibling frames
MapFramesToBones(Frame->Sibling);
}
HRESULT cMesh::Free()
{
m_Graphics = NULL;
m_NumMeshes = 0;
delete m_Meshes;
m_Meshes = NULL;
m_NumFrames = 0;
delete m_Frames;
m_Frames = NULL;
m_Min.x = m_Min.y = m_Min.z = m_Max.x = m_Max.y = m_Max.z = 0.0f;
m_Radius = 0.0f;
return S_OK;
}
sFrame *cMesh::GetFrame(char *Name)
{
if(m_Frames == NULL)
return NULL;
return m_Frames->FindFrame(Name);
}
long cMesh::GetNumFrames()
{
return m_NumFrames;
}
sFrame *cMesh::GetParentFrame()
{
return m_Frames;
}
long cMesh::GetNumMeshes()
{
return m_NumMeshes;
}
sMesh *cMesh::GetParentMesh()
{
return m_Meshes;
}
sMesh *cMesh::GetMesh(char *Name)
{
if(m_Meshes == NULL)
return NULL;
return m_Meshes->FindMesh(Name);
}
BOOL cMesh::GetBounds(float *MinX, float *MinY, float *MinZ, float *MaxX, float *MaxY, float *MaxZ, float *Radius)
{
if(MinX != NULL)
*MinX = m_Min.x;
if(MinY != NULL)
*MinY = m_Min.y;
if(MinZ != NULL)
*MinZ = m_Min.z;
if(MaxX != NULL)
*MaxX = m_Max.x;
if(MaxY != NULL)
*MaxY = m_Max.y;
if(MaxZ != NULL)
*MaxZ = m_Max.z;
if(Radius != NULL)
*Radius = m_Radius;
return TRUE;
}
以前修改《DirectX 高级动画制作》 加载模型的代码,DX 9.0C化 |
|