📄 meshloader.cpp
字号:
//=============================================================================
// File: MeshLoader.cpp
//=============================================================================
#include "dxstdafx.h"
#pragma warning(disable: 4995)
#include "meshloader.h"
#include <fstream>
#pragma warning(default: 4995)
using namespace std;
//-----------------------------------------------------------------------------
// Desc: 构造函数
//-----------------------------------------------------------------------------
CMeshLoader::CMeshLoader()
{
m_pd3dDevice = NULL;
m_pMesh = NULL;
ZeroMemory( m_strMediaDir, sizeof(m_strMediaDir) );
}
//-----------------------------------------------------------------------------
// Desc: 析构函数
//-----------------------------------------------------------------------------
CMeshLoader::~CMeshLoader()
{
Destroy();
}
//-----------------------------------------------------------------------------
// Desc: 释放网格模型材质、纹理已经网格模型对象
//-----------------------------------------------------------------------------
void CMeshLoader::Destroy()
{
//释放材质和纹理
for( int iMaterial=0; iMaterial < m_Materials.GetSize(); iMaterial++ )
{
Material* pMaterial = m_Materials.GetAt( iMaterial );
//避免对同一纹理对象释放两次
for( int x=iMaterial+1; x < m_Materials.GetSize(); x++ )
{
Material* pCur = m_Materials.GetAt( x );
if( pCur->pTexture == pMaterial->pTexture )
pCur->pTexture = NULL;
}
SAFE_RELEASE( pMaterial->pTexture );
SAFE_DELETE( pMaterial );
}
m_Materials.RemoveAll();
m_Vertices.RemoveAll();
m_Indices.RemoveAll();
m_Attributes.RemoveAll();
//释放网格模型
SAFE_RELEASE( m_pMesh );
m_pd3dDevice = NULL;
}
//-----------------------------------------------------------------------------
// Desc: 创建网格模型相关对象
//-----------------------------------------------------------------------------
HRESULT CMeshLoader::Create( IDirect3DDevice9* pd3dDevice, const WCHAR* strFilename )
{
HRESULT hr;
WCHAR str[ MAX_PATH ] = {0};
//先释放原来的相关内容
Destroy();
//保存设备指针
m_pd3dDevice = pd3dDevice;
//从指定.obj文件加载相关对象
V_RETURN( LoadGeometryFromOBJ( strFilename ) );
//保存当前完整
WCHAR wstrOldDir[MAX_PATH] = {0};
GetCurrentDirectory( MAX_PATH, wstrOldDir );
SetCurrentDirectory( m_strMediaDir );
//提取材质和纹理
for( int iMaterial=0; iMaterial < m_Materials.GetSize(); iMaterial++ )
{
Material* pMaterial = m_Materials.GetAt( iMaterial );
if( pMaterial->strTexture[0] )
{
//避免创建相同的纹理两次
bool bFound = false;
for( int x=0; x < iMaterial; x++ )
{
Material* pCur = m_Materials.GetAt( x );
if( 0 == wcscmp( pCur->strTexture, pMaterial->strTexture ) )
{
bFound = true;
pMaterial->pTexture = pCur->pTexture;
break;
}
}
//创建纹理
if( !bFound )
{
//应先从纹理文件路径中提取纹理文件名
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, pMaterial->strTexture ) );
V_RETURN( D3DXCreateTextureFromFile( pd3dDevice, str, //pMaterial->strTexture,
&(pMaterial->pTexture )));
}
}
}
//恢复当前路径
SetCurrentDirectory( wstrOldDir );
//创建网格对象
ID3DXMesh* pMesh = NULL;
V_RETURN( D3DXCreateMeshFVF( m_Indices.GetSize() / 3, m_Vertices.GetSize(),
D3DXMESH_MANAGED | D3DXMESH_32BIT,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
pd3dDevice, &pMesh ) );
//复制顶点数据到网格对象
VERTEX* pVertex;
V_RETURN( pMesh->LockVertexBuffer( 0, (void**) &pVertex ) );
memcpy( pVertex, m_Vertices.GetData(), m_Vertices.GetSize() * sizeof(VERTEX) );
pMesh->UnlockVertexBuffer();
m_Vertices.RemoveAll();
//复制索引数据到网格对象
DWORD* pIndex;
V_RETURN( pMesh->LockIndexBuffer( 0, (void**) &pIndex ) );
memcpy( pIndex, m_Indices.GetData(), m_Indices.GetSize() * sizeof(DWORD) );
pMesh->UnlockIndexBuffer();
m_Indices.RemoveAll();
//复制属性数据到网格对象
DWORD* pSubset;
V_RETURN( pMesh->LockAttributeBuffer( 0, &pSubset ) );
memcpy( pSubset, m_Attributes.GetData(), m_Attributes.GetSize() * sizeof(DWORD) );
pMesh->UnlockAttributeBuffer();
m_Attributes.RemoveAll();
//对网格模型进行优化
DWORD* aAdjacency = new DWORD[pMesh->GetNumFaces() * 3];
if( aAdjacency == NULL )
return E_OUTOFMEMORY;
V( pMesh->GenerateAdjacency(1e-6f,aAdjacency) );
V( pMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, aAdjacency, NULL, NULL, NULL) );
SAFE_DELETE_ARRAY( aAdjacency );
m_pMesh = pMesh;
return S_OK;
}
//-----------------------------------------------------------------------------
// Desc: 从.obj文件加载数据
//-----------------------------------------------------------------------------
HRESULT CMeshLoader::LoadGeometryFromOBJ( const WCHAR* strFileName )
{
WCHAR strMaterialFilename[MAX_PATH] = {0};
WCHAR wstr[MAX_PATH];
char str[MAX_PATH];
HRESULT hr;
//根据文件名查找文件
V_RETURN( DXUTFindDXSDKMediaFileCch( wstr, MAX_PATH, strFileName ) );
WideCharToMultiByte( CP_ACP, 0, wstr, -1, str, MAX_PATH, NULL, NULL );
//保存.obj文件完整路径
StringCchCopy( m_strMediaDir, MAX_PATH-1, wstr );
WCHAR* pch = wcsrchr( m_strMediaDir, L'\\' );
if( pch )
*pch = NULL;
//为顶点位置坐标、纹理坐标和法线数据创建临时存储空间
CGrowableArray< D3DXVECTOR3 > Positions;
CGrowableArray< D3DXVECTOR2 > TexCoords;
CGrowableArray< D3DXVECTOR3 > Normals;
//第一个子网格使用默认材质
Material* pMaterial = new Material();
if( pMaterial == NULL )
return E_OUTOFMEMORY;
InitMaterial( pMaterial );
StringCchCopy( pMaterial->strName, MAX_PATH-1, L"default" );
m_Materials.Add( pMaterial );
DWORD dwCurSubset = 0;
// File input
WCHAR strCommand[256] = {0};
wifstream InFile( str );
if( !InFile )
return DXTRACE_ERR( L"wifstream::open", E_FAIL );
for(;;)
{
InFile >> strCommand;
if( !InFile )
break;
if( 0 == wcscmp( strCommand, L"#" ) )
{
// Comment
}
else if( 0 == wcscmp( strCommand, L"v" ) )
{
// Vertex Position
float x, y, z;
InFile >> x >> y >> z;
Positions.Add( D3DXVECTOR3( x, y, z ) );
}
else if( 0 == wcscmp( strCommand, L"vt" ) )
{
// Vertex TexCoord
float u, v;
InFile >> u >> v;
TexCoords.Add( D3DXVECTOR2( u, v ) );
}
else if( 0 == wcscmp( strCommand, L"vn" ) )
{
// Vertex Normal
float x, y, z;
InFile >> x >> y >> z;
Normals.Add( D3DXVECTOR3( x, y, z ) );
}
else if( 0 == wcscmp( strCommand, L"f" ) )
{
// Face
UINT iPosition, iTexCoord, iNormal;
VERTEX vertex;
for( UINT iFace=0; iFace < 3; iFace++ )
{
ZeroMemory( &vertex, sizeof(VERTEX) );
// OBJ format uses 1-based arrays
InFile >> iPosition;
vertex.position = Positions[ iPosition-1 ];
if( '/' == InFile.peek() )
{
InFile.ignore();
if( '/' != InFile.peek() )
{
// Optional texture coordinate
InFile >> iTexCoord;
vertex.texcoord = TexCoords[ iTexCoord-1 ];
}
if( '/' == InFile.peek() )
{
InFile.ignore();
// Optional vertex normal
InFile >> iNormal;
vertex.normal = Normals[ iNormal-1 ];
}
}
// If a duplicate vertex doesn't exist, add this vertex to the Vertices
// list. Store the index in the Indices array. The Vertices and Indices
// lists will eventually become the Vertex Buffer and Index Buffer for
// the mesh.
DWORD index = AddVertex( iPosition, &vertex );
m_Indices.Add( index );
}
m_Attributes.Add( dwCurSubset );
}
else if( 0 == wcscmp( strCommand, L"mtllib" ) )
{
// Material library
InFile >> strMaterialFilename;
}
else if( 0 == wcscmp( strCommand, L"usemtl" ) )
{
// Material
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -