在DirectX的Mesh文件中,通常一个纹理可能作被几个材质共用。这是因为顶点是以属性分组的,只要材质和纹理不一样,就需要使用不同的属性。 而在一般的建模软件中,纹理常常被当成材质的一部分,导出时每个“材质”都有自己的纹理,这样做也是因为有时Mesh在不同的部分尽管使用相同的纹理,但是有不同的光照特性。DirectX的Mesh也是按照同样的方式组织材质,纹理和网格。
DirectX提供的案例中,每个材质都分别加载一个纹理,可是,调试程序的时候,你会发现,有时只有几个纹理的物体,加载上来,有十几个材质,这样显然会有纹理被反复加载,那么我们可以使用COM的参照计数来避免这个问题。
在加载一个材质对应纹理之前,先找一下前面的纹理有没有同名的,如果有,就把那个纹理的指针拷贝到这个材质对应的纹理指针,同时给这个被拷贝指针的纹理加上一个参考。那么以后释放它的时候就不用担心前面一个是否已经被释放了。
COM是参照计数的,当增加一个参考时,计数器加1,释放一次时,计数器减1,如果计数器减到0,就把它从内存中释放掉。如果是使用了智能的指针,这个问题就更简单了,直接拷贝就可以了:
m_pMeshTextures[i]=m_pMeshTextures[j];
在DirectX的类型声明中可以看到,LPDIRECT3DTEXTURE9并不是一个智能指针:
typedef struct IDirect3DTexture9 *LPDIRECT3DTEXTURE9, *PDIRECT3DTEXTURE9;
所以在拷贝指针后要给这个COM对象的参考加1
m_pMeshTextures[j]->AddRef();
m_pMeshMaterials = new D3DMATERIAL9[m_dwNumOfMaterials]; //材质指针数组
m_pMeshTextures = new LPDIRECT3DTEXTURE9[m_dwNumOfMaterials]; //纹理指针数组
for(DWORD i=0; i<m_dwNumOfMaterials; i++ )
{
m_pMeshMaterials[i] = d3dxMaterials[i].MatD3D; //从缓冲区中拷贝材质
m_pMeshMaterials[i].Ambient = m_pMeshMaterials[i].Diffuse; //设置环境光属性
m_pMeshTextures[i] = NULL; //初始成空
//根据材质中的纹理文件名加载纹理
DWORD j=0;
while(j<i)
{ //避免重复加载纹理
if(0==strcmp(d3dxMaterials[j].pTextureFilename, d3dxMaterials[i].pTextureFilename)) //找到同名纹理的序号
{
m_pMeshTextures[i]=m_pMeshTextures[j]; //直接拷贝指针而不是加载一次
m_pMeshTextures[j]->AddRef(); //参考加1
break;
};
j++;
}
if(! m_pMeshTextures[i])
{
D3DXCreateTextureFromFile( m_pDevice,
d3dxMaterials[i].pTextureFilename, &m_pMeshTextures[i] );
}
}
m_pMeshTextures = new LPDIRECT3DTEXTURE9[m_dwNumOfMaterials]; //纹理指针数组
for(DWORD i=0; i<m_dwNumOfMaterials; i++ )
{
m_pMeshMaterials[i] = d3dxMaterials[i].MatD3D; //从缓冲区中拷贝材质
m_pMeshMaterials[i].Ambient = m_pMeshMaterials[i].Diffuse; //设置环境光属性
m_pMeshTextures[i] = NULL; //初始成空
//根据材质中的纹理文件名加载纹理
DWORD j=0;
while(j<i)
{ //避免重复加载纹理
if(0==strcmp(d3dxMaterials[j].pTextureFilename, d3dxMaterials[i].pTextureFilename)) //找到同名纹理的序号
{
m_pMeshTextures[i]=m_pMeshTextures[j]; //直接拷贝指针而不是加载一次
m_pMeshTextures[j]->AddRef(); //参考加1
break;
};
j++;
}
if(! m_pMeshTextures[i])
{
D3DXCreateTextureFromFile( m_pDevice,
d3dxMaterials[i].pTextureFilename, &m_pMeshTextures[i] );
}
}
在释放时,按照正常的方法释放就可以了
for(DWORD i=0; i<m_dwNumOfMaterials; i++ )
{
SAFE_RELEASE(m_pMeshTextures[i]);
}
SAFE_DELETE_ARRAY(m_pMeshTextures);
SAFE_DELETE_ARRAY(m_pMeshMaterials);
{
SAFE_RELEASE(m_pMeshTextures[i]);
}
SAFE_DELETE_ARRAY(m_pMeshTextures);
SAFE_DELETE_ARRAY(m_pMeshMaterials);