在游戏中,像树,石头等物体在地图上通常要渲染很多个,如果每个模型都是加载 新资源,这样加载时间会非常长,占用内存也会非常多。所以我们利用缓存来解决这个问题。如果是新资源就加载,如果加载过就读取缓存中的。
我们封装一个类来保存节点的缓存,其中包括Lod的层级模型,文件名(.x),材质层数,材质指针,以及其他的功能的函数:
typedef class CDXMeshNode
{
public:
CDXMeshNode(LPDIRECT3DDEVICE9 DVC,void* Parent );
~CDXMeshNode();
LPD3DXMESH GenMesh;
LPD3DXMESH LODMeshs[MAXLODLEVEL];
int Index;
D3DMATERIAL9 *mMat;
DWORD mAttCount;
char* mName;
HRESULT QCreate(char* sName);
void QUsing();
void QRelease();
void Render(short iLOD,bool UserSelfMat,LPDIRECT3DTEXTURE9* Face);
HRESULT MakeMeshLOD(DWORD* pAdj);
private:
void *mParent;
LPDIRECT3DDEVICE9 mDVC;
int mRef;
HRESULT LoadFromFile();
}*LPMESHNODE;
我们曾经类CDXMeshBuffer来管理节点类(方便对节点的获取和析构),把节点类存储在一个EasyList中。
class CDXMeshBuffer
{
public:
CDXMeshBuffer(void){};
public:
~CDXMeshBuffer(void){};
void Init(LPDIRECT3DDEVICE9 DVC);
LPMESHNODE QCreateMesh(char* sFile);
HRESULT QReleaseMesh(char* sFile);
DWORD GetMeshCount();
HRESULT ReleaseAll();
HRESULT DeleteMesh(char* sFile);
private:
LPDIRECT3DDEVICE9 mDVC;
CEasyList mMeshes;
LPMESHNODE GetMeshNodeByName(char* sFile);
};
extern CDXMeshBuffer gMeshBuffer;
两个类的实现:
CDXMeshNode::CDXMeshNode( LPDIRECT3DDEVICE9 DVC ,void* Parent )
{
mMat=NULL;
Index=-1;
mAttCount=0;;
mName=NULL;
mDVC=DVC;
mParent=Parent;
GenMesh=NULL;
ZeroMemory(LODMeshs,MAXLODLEVEL*sizeof(LPD3DXMESH));
mRef=0;
}
HRESULT CDXMeshNode::QCreate( char* sName )
{
mName=new char[strlen(sName)+1];
strcpy(mName,sName);
HRESULT hr= LoadFromFile();
if (!FAILED(hr))
{
mRef++;
}
return hr;
}
void CDXMeshNode::QUsing( )
{
mRef++;
}
void CDXMeshNode::QRelease()
{
mRef--;
if (mRef<1)
{
if (mParent)
{
((CDXMeshBuffer*)mParent)->DeleteMesh(mName);
}
}
}
CDXMeshNode::~CDXMeshNode( void )
{
if(mRef>0) return ;
if (GenMesh)
{
SAFE_RELEASE(GenMesh);
}
for (int i=0;i<MAXLODLEVEL;i++)
{
if (LODMeshs[i])
{
SAFE_RELEASE(LODMeshs[i]);
}
}
if (mMat)
{
delete mMat;
}
if (mName)
{
delete []mName;
mName=NULL;
}
}
HRESULT CDXMeshNode::LoadFromFile( )
{
HRESULT hr;
LPD3DXMESH pMesh;
LPD3DXBUFFER pAdj;
LPD3DXBUFFER pMat;
hr=D3DXLoadMeshFromXA(mName,
D3DXMESH_MANAGED, mDVC, &pAdj,
&pMat, NULL, &mAttCount, &pMesh) ;
if (FAILED(hr)) return hr;
GenMesh=pMesh;
hr=MakeMeshLOD((DWORD*)pAdj->GetBufferPointer());
mMat=new D3DMATERIAL9[mAttCount];
ZeroMemory(mMat,mAttCount*sizeof(D3DMATERIAL9));
D3DXMATERIAL *pMatList;
pMatList=(D3DXMATERIAL *)pMat->GetBufferPointer();
for (int i=0;i<mAttCount;i++)
{
mMat[i]=pMatList[i].MatD3D;
mMat[i].Ambient.a=0.3;
mMat[i].Ambient.r=0.3;
mMat[i].Ambient.g=0.3;
mMat[i].Ambient.b=0.3;
}
SAFE_RELEASE(pAdj);
SAFE_RELEASE(pMat);
if (FAILED(hr)) return hr;
return S_OK;
}
void CDXMeshNode::Render( short iLOD,bool UserSelfMat,LPDIRECT3DTEXTURE9* Face )
{
for (int i=0;i<mAttCount;i++)
{
if (!LODMeshs[i])
{
continue;
}
if (UserSelfMat)
{
mDVC->SetMaterial(&mMat[i]);
}
if (Face)
{
mDVC->SetTexture(0,Face[i]);
}
LODMeshs[i]->DrawSubset(i);
}
}
HRESULT CDXMeshNode::MakeMeshLOD( DWORD* pAdj )
{
HRESULT hr;
if ((GenMesh==NULL) || (pAdj==NULL) )
{
return S_FALSE;
}
LPD3DXMESH pTempMesh =NULL; //临时网格模型变量
//清理
hr = D3DXCleanMesh( D3DXCLEAN_SIMPLIFICATION, GenMesh,pAdj,&pTempMesh,pAdj, NULL ) ;
if (FAILED(hr)) return hr;
GenMesh->Release();
GenMesh = pTempMesh;
//焊接
D3DXWELDEPSILONS Epsilons;
ZeroMemory( &Epsilons, sizeof(D3DXWELDEPSILONS) );
Epsilons.Normal=0.01;
Epsilons.Position=0.1;
hr = D3DXWeldVertices( GenMesh,D3DXWELDEPSILONS_WELDPARTIALMATCHES,
&Epsilons,pAdj,pAdj, NULL, NULL );
if (FAILED(hr)) return hr;
//检查对原始网格模型进行整理、简化之后,还需要检查处理后的网格模型是否有效
hr = D3DXValidMesh( GenMesh, pAdj, NULL );
if (FAILED(hr)) return hr;
DWORD MaxVetex=GenMesh->GetNumVertices();
LPD3DXPMESH ppMesh=NULL;
hr = D3DXGeneratePMesh( GenMesh, pAdj,NULL, NULL, 1, D3DXMESHSIMP_VERTEX, &ppMesh );
if (FAILED(hr)) return hr;
MaxVetex=GenMesh->GetNumVertices();
for (int i=0;i<MAXLODLEVEL;i++)
{
ppMesh->SetNumVertices(MaxVetex*0.8);
hr=ppMesh->CloneMeshFVF(ppMesh->GetOptions(),ppMesh->GetFVF(),mDVC,&LODMeshs[i]);
if (FAILED(hr)) return hr;
MaxVetex=LODMeshs[i]->GetNumVertices();
MaxVetex=ppMesh->GetNumVertices();
if( !(LODMeshs[i]->GetFVF() & D3DFVF_NORMAL) )
{
ID3DXMesh* pTempMesh;
hr=LODMeshs[i]->CloneMeshFVF( LODMeshs[i]->GetOptions(),
LODMeshs[i]->GetFVF() | D3DFVF_NORMAL,
mDVC, &pTempMesh ) ;
SAFE_RELEASE( LODMeshs[i] );
LODMeshs[i] = pTempMesh;
}
hr=D3DXComputeNormals( LODMeshs[i], NULL ) ;
}
SAFE_RELEASE(ppMesh);
return S_OK;
}
LPMESHNODE CDXMeshBuffer::QCreateMesh( char* sFile )
{
LPMESHNODE pMeshNode=NULL;
pMeshNode=GetMeshNodeByName(sFile);
if (!pMeshNode)
{
pMeshNode =new CDXMeshNode(mDVC,this);
pMeshNode->QCreate(sFile);
mMeshes.Add(pMeshNode);
}else
{
pMeshNode->QUsing();
}
return pMeshNode;
}
LPMESHNODE CDXMeshBuffer::GetMeshNodeByName( char* sFile )
{
LPMESHNODE pMeshNode=NULL;
CListCursor Cursor;
Cursor.Create(&mMeshes);
pMeshNode=(LPMESHNODE)(Cursor.First());
int i=0;
while(pMeshNode)
{
if (strcmp(pMeshNode->mName,sFile)==0)
{
pMeshNode->Index=i;
return pMeshNode;
}
i++;
pMeshNode=(LPMESHNODE)(Cursor.Next());
}
return NULL;
}
HRESULT CDXMeshBuffer::QReleaseMesh( char* sFile )
{
return S_OK;
}
DWORD CDXMeshBuffer::GetMeshCount()
{
return mMeshes.Count();
}
HRESULT CDXMeshBuffer::ReleaseAll()
{
return S_OK;
}
void CDXMeshBuffer::Init( LPDIRECT3DDEVICE9 DVC )
{
mDVC=DVC;
}
HRESULT CDXMeshBuffer::DeleteMesh( char* sFile )
{
LPMESHNODE pNode=(LPMESHNODE)(GetMeshNodeByName(sFile));
if (pNode>=0)
{
if (pNode->Index>=0)
{
mMeshes.Delete(pNode->Index);
}
delete pNode;
}
return S_OK;
}
CDXMeshBuffer gMeshBuffer;
浙公网安备 33010602011771号