//----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- HRESULT CD3DMesh::SetFVF( LPDIRECT3DDEVICE9 pd3dDevice, DWORD dwFVF ) { LPD3DXMESH pTempSysMemMesh = NULL; LPD3DXMESH pTempLocalMesh = NULL; if( m_pSysMemMesh ) { if( FAILED( m_pSysMemMesh->CloneMeshFVF( D3DXMESH_SYSTEMMEM, dwFVF, pd3dDevice, &pTempSysMemMesh ) ) ) return E_FAIL; } if( m_pLocalMesh ) { if( FAILED( m_pLocalMesh->CloneMeshFVF( 0L, dwFVF, pd3dDevice, &pTempLocalMesh ) ) ) { SAFE_RELEASE( pTempSysMemMesh ); return E_FAIL; } } SAFE_RELEASE( m_pSysMemMesh ); SAFE_RELEASE( m_pLocalMesh ); if( pTempSysMemMesh ) m_pSysMemMesh = pTempSysMemMesh; if( pTempLocalMesh ) m_pLocalMesh = pTempLocalMesh; // Compute normals in case the meshes have them if( m_pSysMemMesh ) D3DXComputeNormals( m_pSysMemMesh, NULL ); if( m_pLocalMesh ) D3DXComputeNormals( m_pLocalMesh, NULL ); return S_OK; }
HRESULT LoadMesh(IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh) { ID3DXMesh* pMesh = NULL; WCHAR str[MAX_PATH]; HRESULT hr; V_RETURN(DXUTFindDXSDKMediaFileCch(str, MAX_PATH, strFileName)); V_RETURN(D3DXLoadMeshFromX(str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, &pMesh)); DWORD* rgdwAdjacency = NULL; if(!(pMesh->GetFVF() & D3DFVF_NORMAL)) { ID3DXMesh* pTempMesh; V(pMesh->CloneMeshFVF(pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pd3dDevice, &pTempMesh)); V(D3DXComputeNormals(pTempMesh, NULL)); SAFE_RELEASE(pMesh); pMesh = pTempMesh; } rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3]; if(rgdwAdjacency == NULL) return E_OUTOFMEMORY; V(pMesh->GenerateAdjacency(1e-6f, rgdwAdjacency)); V(pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL)); delete []rgdwAdjacency; *ppMesh = pMesh; return S_OK; }
//----------------------------------------------------------------------------- HRESULT CDXUTMesh::SetFVF( LPDIRECT3DDEVICE9 pd3dDevice, DWORD dwFVF ) { LPD3DXMESH pTempMesh = NULL; if( m_pMesh ) { if( FAILED( m_pMesh->CloneMeshFVF( m_pMesh->GetOptions(), dwFVF, pd3dDevice, &pTempMesh ) ) ) { SAFE_RELEASE( pTempMesh ); return E_FAIL; } DWORD dwOldFVF = 0; dwOldFVF = m_pMesh->GetFVF(); SAFE_RELEASE( m_pMesh ); m_pMesh = pTempMesh; // Compute normals if they are being requested and // the old mesh does not have them. if( !(dwOldFVF & D3DFVF_NORMAL) && dwFVF & D3DFVF_NORMAL ) { D3DXComputeNormals( m_pMesh, NULL ); } } return S_OK; }
//初期化。 void Model::Init(LPDIRECT3DDEVICE9 pd3dDevice, const char* fileName) { Release(); //Xファイルをロード。 LPD3DXBUFFER pD3DXMtrlBuffer; //Xファイルのロード。 D3DXLoadMeshFromX(fileName, D3DXMESH_SYSTEMMEM, pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &numMaterial, &mesh); //法線が存在するか調べる。 if ((mesh->GetFVF() & D3DFVF_NORMAL) == 0) { //法線がないので作成する。 ID3DXMesh* pTempMesh = NULL; mesh->CloneMeshFVF(mesh->GetOptions(), mesh->GetFVF() | D3DFVF_NORMAL, g_pd3dDevice, &pTempMesh); D3DXComputeNormals(pTempMesh, NULL); mesh->Release(); mesh = pTempMesh; } // マテリアルバッファを取得。 D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); //テクスチャをロード。 textures = new LPDIRECT3DTEXTURE9[numMaterial]; for (DWORD i = 0; i < numMaterial; i++) { textures[i] = NULL; //テクスチャを作成する。 D3DXCreateTextureFromFileA(pd3dDevice, d3dxMaterials[i].pTextureFilename, &textures[i]); } // マテリアルバッファを解放。 pD3DXMtrlBuffer->Release(); //シェーダーをコンパイル。 LPD3DXBUFFER compileErrorBuffer = NULL; //シェーダーをコンパイル。 HRESULT hr = D3DXCreateEffectFromFile( pd3dDevice, "basic.fx", NULL, NULL, D3DXSHADER_SKIPVALIDATION, NULL, &effect, &compileErrorBuffer ); if (hr != S_OK) { MessageBox(NULL, (char*)(compileErrorBuffer->GetBufferPointer()), "error", MB_OK); std::abort(); } }
// // MeshNode::VOnRestore - 3rd Edition, Chapter 14, page 506 // // This function loads the Mesh and ensures the Mesh has normals; it also optimizes the // Mesh for the graphics card's vertex cache, which improves performance by organizing // the internal triangle list for less cache misses. // HRESULT D3DMeshNode9::VOnRestore(Scene *pScene) { if (m_XFileName.empty()) { SetRadius(CalcBoundingSphere()); return D3DSceneNode9::VOnRestore(pScene); } // Change post press - release the Mesh only if we have a valid Mesh file name to load. // Otherwise we likely created it on our own, and needs to be kept. SAFE_RELEASE(m_pMesh); WCHAR str[MAX_PATH]; HRESULT hr; // Load the Mesh with D3DX and get back a ID3DXMesh*. For this // sample we'll ignore the X file's embedded materials since we know // exactly the model we're loading. See the Mesh samples such as // "OptimizedMesh" for a more generic Mesh loading example. V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, m_XFileName.c_str() ) ); V_RETURN( D3DXLoadMeshFromX(str, D3DXMESH_MANAGED, DXUTGetD3D9Device(), NULL, NULL, NULL, NULL, &m_pMesh) ); DWORD *rgdwAdjacency = NULL; // Make sure there are normals which are required for lighting if( !(m_pMesh->GetFVF() & D3DFVF_NORMAL) ) { ID3DXMesh* pTempMesh; V( m_pMesh->CloneMeshFVF( m_pMesh->GetOptions(), m_pMesh->GetFVF() | D3DFVF_NORMAL, DXUTGetD3D9Device(), &pTempMesh ) ); V( D3DXComputeNormals( pTempMesh, NULL ) ); SAFE_RELEASE( m_pMesh ); m_pMesh = pTempMesh; } // Optimize the Mesh for this graphics card's vertex cache // so when rendering the Mesh's triangle list the vertices will // cache hit more often so it won't have to re-execute the vertex shader // on those vertices so it will improve perf. rgdwAdjacency = GCC_NEW DWORD[m_pMesh->GetNumFaces() * 3]; if( rgdwAdjacency == NULL ) return E_OUTOFMEMORY; V( m_pMesh->ConvertPointRepsToAdjacency(NULL, rgdwAdjacency) ); V( m_pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL) ); SAFE_DELETE_ARRAY(rgdwAdjacency); SetRadius(CalcBoundingSphere()); return D3DSceneNode9::VOnRestore(pScene); }
//----------------------------------------------------------------------------- // Name: CD3DMesh::SetVertexDecl // Desc: Convert the mesh to the format specified by the given vertex // declarations. //----------------------------------------------------------------------------- HRESULT CD3DMesh::SetVertexDecl( LPDIRECT3DDEVICE9 pd3dDevice, D3DVERTEXELEMENT9 *pDecl ) { LPD3DXMESH pTempSysMemMesh = NULL; LPD3DXMESH pTempLocalMesh = NULL; if( m_pSysMemMesh ) { if( FAILED( m_pSysMemMesh->CloneMesh( D3DXMESH_SYSTEMMEM, pDecl, pd3dDevice, &pTempSysMemMesh ) ) ) return E_FAIL; } if( m_pLocalMesh ) { if( FAILED( m_pLocalMesh->CloneMesh( 0L, pDecl, pd3dDevice, &pTempLocalMesh ) ) ) { SAFE_RELEASE( pTempSysMemMesh ); return E_FAIL; } } SAFE_RELEASE( m_pSysMemMesh ); SAFE_RELEASE( m_pLocalMesh ); if( pTempSysMemMesh ) { m_pSysMemMesh = pTempSysMemMesh; // Compute normals in case the meshes have them D3DXComputeNormals( m_pSysMemMesh, NULL ); } if( pTempLocalMesh ) { m_pLocalMesh = pTempLocalMesh; // Compute normals in case the meshes have them D3DXComputeNormals( m_pLocalMesh, NULL ); } return S_OK; }
ID3DXMesh* Mesh::GenerateNormals(ID3DXMesh* mesh, IDirect3DDevice9* d3d9Device) { // see if we have texture coordinates D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; DXCall(mesh->GetDeclaration(decl)); bool foundTexCoord = false; for (UINT i = 0; i < MAX_FVF_DECL_SIZE; ++i) { if (decl[i].Stream == 0xFF) break; else if(decl[i].Usage == D3DDECLUSAGE_TEXCOORD && decl[i].UsageIndex == 0) { foundTexCoord = true; break; } } // Clone the mesh with a new declaration D3DVERTEXELEMENT9 tcDecl[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; D3DVERTEXELEMENT9 noTCDecl[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; D3DVERTEXELEMENT9* newDecl; if (foundTexCoord) newDecl = tcDecl; else newDecl = noTCDecl; ID3DXMesh* clonedMesh = NULL; UINT options = D3DXMESH_MANAGED; if (indexType == Index32Bit) options |= D3DXMESH_32BIT; DXCall(mesh->CloneMesh(options, newDecl, d3d9Device, &clonedMesh)); mesh->Release(); // Generate the normals DXCall(D3DXComputeNormals(clonedMesh, &adjacency[0])); return clonedMesh; }
void MeshX::BuildSkinnedMesh() { ID3DXMesh* oldMesh = allocMeshHierarchy.GetMeshList().front()->MeshData.pMesh; //compute normal D3DVERTEXELEMENT9 elements[MAX_FVF_DECL_SIZE]; oldMesh->GetDeclaration(elements); ID3DXMesh* tempMesh = 0; ID3DXMesh* tempOpMesh = 0; oldMesh->CloneMesh(D3DXMESH_SYSTEMMEM, elements, pDevice, &tempMesh); if( !HasNormals(tempMesh) ) D3DXComputeNormals(tempMesh, 0); //optimize the mesh DWORD* adj = new DWORD[tempMesh->GetNumFaces()*3]; ID3DXBuffer* remap = 0; tempMesh->GenerateAdjacency(0.00001f, adj); tempMesh->Optimize(D3DXMESH_SYSTEMMEM | D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_ATTRSORT, adj, 0, 0, &remap, &tempOpMesh); SafeRelease(tempMesh); // In the .X file (specifically the array DWORD vertexIndices[nWeights] // data member of the SkinWeights template) each bone has an array of // indices which identify the vertices of the mesh that the bone influences. // Because we have just rearranged the vertices (from optimizing), the vertex // indices of a bone are obviously incorrect (i.e., they index to vertices the bone // does not influence since we moved vertices around). In order to update a bone's // vertex indices to the vertices the bone _does_ influence, we simply need to specify // where we remapped the vertices to, so that the vertex indices can be updated to // match. This is done with the ID3DXSkinInfo::Remap method. skinInfo->Remap(tempOpMesh->GetNumVertices(), (DWORD*)remap->GetBufferPointer()); SafeRelease(remap); // Done with remap info. DWORD numBoneComboEntries = 0; ID3DXBuffer* boneComboTable = 0; DWORD maxVertInfluences; skinInfo->ConvertToIndexedBlendedMesh(tempOpMesh, 0, 128, 0, 0, 0, 0, &maxVertInfluences, &numBoneComboEntries, &boneComboTable, &this->mesh); SafeRelease(tempOpMesh); SafeRelease(boneComboTable); delete[] adj; }
//------------------------------------------------------------- // Name: RestoreDeviceObjects() // Desc: 화면크기가 변했을때 호출됨 // 확보한 메모리는 InvalidateDeviceObjects()에서 해제 //------------------------------------------------------------- HRESULT CMyD3DApplication::RestoreDeviceObjects() { // 이펙트 if(m_pEffect) m_pEffect->OnResetDevice(); // 메시 m_pMeshBg->RestoreDeviceObjects( m_pd3dDevice ); //--------------------------------------------------------- // FVF로 처리하지 않은 정점선언은 직접 처리 //--------------------------------------------------------- if( m_pMesh && m_pMesh->GetSysMemMesh() ){ LPD3DXMESH pMesh; m_pMesh->GetSysMemMesh()->CloneMesh( m_pMesh->GetSysMemMesh()->GetOptions(), decl, m_pd3dDevice, &pMesh ); D3DXComputeNormals( pMesh, NULL ); D3DXComputeTangent( pMesh, 0, 0, 0, TRUE, NULL ); SAFE_RELEASE(m_pMesh->m_pLocalMesh); m_pMesh->m_pLocalMesh = pMesh; } // 렌더링 상태설정 RS( D3DRS_ZENABLE, TRUE ); RS( D3DRS_LIGHTING, FALSE ); SAMP( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); SAMP( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); SAMP( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP ); SAMP( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP ); // 뷰행렬 D3DXVECTOR3 vFromPt = D3DXVECTOR3( 0.0f, 0.0f, -5.0f ); D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &m_mView, &vFromPt, &vLookatPt, &vUpVec ); // 투영행렬 FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height; D3DXMatrixPerspectiveFovLH( &m_mProj, D3DX_PI/4, fAspect, 1.0f, 100.0f ); // 폰트 m_pFont->RestoreDeviceObjects(); return S_OK; }
HRESULT Mesh::AdjustMeshDecl() { HRESULT hr; LPD3DXMESH pInMesh = mMesh; LPD3DXMESH pOutMesh = NULL; D3DVERTEXELEMENT9 vertDecl[ MAX_FVF_DECL_SIZE ] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // exact SH-coefficients {0, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0}, {0, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 1}, {0, 64, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 2}, {0, 80, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 3}, {0, 96, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 4}, {0, 112, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 5}, {0, 128, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 6}, {0, 144, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 7}, {0, 160, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 8}, {0, 176, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 2}, {0, 188, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 3}, D3DDECL_END() }; hr = pInMesh->CloneMesh( pInMesh->GetOptions(), vertDecl, mDevice, &pOutMesh ); PD( hr, L"clone mesh" ); if( FAILED(hr) ) return hr; if( !DoesMeshHaveUsage( D3DDECLUSAGE_NORMAL ) ) { hr = D3DXComputeNormals( pOutMesh, NULL ); PD( hr, L"compute normals" ); if( FAILED(hr) ) return hr; } ReleaseCOM( pInMesh ) mMesh = pOutMesh; return D3D_OK; }
Mymesh(LPDIRECT3DDEVICE9 pD3DDevice, LPSTR pFilename) { LPD3DXBUFFER materialsBuffer = NULL; LPD3DXMESH mesh = NULL; pd3d = pD3DDevice; // second null is D3DXEFFECTINSTANCE. if (FAILED(D3DXLoadMeshFromX(pFilename, D3DXMESH_SYSTEMMEM, pd3d, NULL, &materialsBuffer, NULL, &dwNumMaterials, &mesh))) { // null everything pMesh = NULL; pMeshMaterials = NULL; pMeshTextures = NULL; return; } D3DXMATERIAL* matMaterials = (D3DXMATERIAL*)materialsBuffer->GetBufferPointer(); pMeshMaterials = new D3DMATERIAL9[dwNumMaterials]; pMeshTextures = new LPDIRECT3DTEXTURE9[dwNumMaterials]; for (DWORD i = 0; i < dwNumMaterials; i++) { pMeshMaterials[i] = matMaterials[i].MatD3D; // ambient color pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse; if (FAILED(D3DXCreateTextureFromFile(pd3d, matMaterials[i].pTextureFilename, &pMeshTextures[i]))) { pMeshTextures[i] = NULL; } } SafeRelease(materialsBuffer); mesh->CloneMeshFVF(D3DXMESH_MANAGED, MESH_D3DFVF_CUSTOMVERTEX, pd3d, &pMesh); SafeRelease(mesh); D3DXComputeNormals(pMesh,0); }
//-------------------------------------------------------------------------------------- // This function loads the mesh and ensures the mesh has normals; it also optimizes the // mesh for the graphics card's vertex cache, which improves performance by organizing // the internal triangle list for less cache misses. //-------------------------------------------------------------------------------------- HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh ) { ID3DXMesh* pMesh = NULL; WCHAR str[MAX_PATH]; HRESULT hr; // Load the mesh with D3DX and get back a ID3DXMesh*. For this // sample we'll ignore the X file's embedded materials since we know // exactly the model we're loading. See the mesh samples such as // "OptimizedMesh" for a more generic mesh loading example. V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, strFileName ) ); V_RETURN( D3DXLoadMeshFromX( str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, &pMesh ) ); DWORD* rgdwAdjacency = NULL; // Make sure there are normals which are required for lighting if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) ) { ID3DXMesh* pTempMesh; V( pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pd3dDevice, &pTempMesh ) ); V( D3DXComputeNormals( pTempMesh, NULL ) ); SAFE_RELEASE( pMesh ); pMesh = pTempMesh; } // Optimize the mesh for this graphics card's vertex cache // so when rendering the mesh's triangle list the vertices will // cache hit more often so it won't have to re-execute the vertex shader // on those vertices so it will improve perf. rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3]; if( rgdwAdjacency == NULL ) return E_OUTOFMEMORY; V( pMesh->GenerateAdjacency( 1e-6f, rgdwAdjacency ) ); V( pMesh->OptimizeInplace( D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL ) ); delete []rgdwAdjacency; *ppMesh = pMesh; return S_OK; }
//-------------------------------------------------------------------------------------- //메쉬 불러오는 함수 //-------------------------------------------------------------------------------------- HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh ) { ID3DXMesh* pMesh = NULL; WCHAR str[MAX_PATH]; HRESULT hr; V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, strFileName ) ); V_RETURN( D3DXLoadMeshFromX( str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, &pMesh ) ); DWORD* rgdwAdjacency = NULL; // mesh에 노말벡터 생성하는 코드 if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) ) { ID3DXMesh* pTempMesh; V( pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pd3dDevice, &pTempMesh ) ); V( D3DXComputeNormals( pTempMesh, NULL ) ); SAFE_RELEASE( pMesh ); pMesh = pTempMesh; } //성능 향상을 도모하고자 인접 정보를 기록 //각 mesh(삼각형) 정보 테이블을 가지는 형태 //해당 정보는 pMesh가 가지고 있음 //각 mesh 정보는 인접할 수 있는 점의 최대 개수가 3개 이내임을 활용해 효율적으로 vertex 운영 rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3]; if( rgdwAdjacency == NULL ) return E_OUTOFMEMORY; V( pMesh->GenerateAdjacency( 1e-6f, rgdwAdjacency ) ); //버텍스 캐쉬를 활용하는 것 V( pMesh->OptimizeInplace( D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL ) ); delete []rgdwAdjacency; //callback out 변수에 최종 값 저장 *ppMesh = pMesh; return S_OK; }
HRESULT AiPathReader::CreateMesh(LPDIRECT3DDEVICE9 pD3DDevice, LPD3DXMESH &pMesh) { //Todo: ID3DXMesh::SetAttributeTable (set materials how they are defined in the face struct) DWORD dwFVF = (D3DFVF_XYZ | D3DFVF_NORMAL); struct D3DVERTEX { D3DXVECTOR3 p; D3DXVECTOR3 n; }; HRESULT r = D3DXCreateMeshFVF(3 * nodes.size(), 3 * nodes.size(), D3DXMESH_MANAGED, dwFVF, pD3DDevice, &pMesh); if(FAILED(r)) { return r; } D3DVERTEX *vertexBuffer; WORD *indexBuffer = nullptr; unsigned long *pAdjacency = new unsigned long[nodes.size() * 3]; pMesh->LockIndexBuffer(0, reinterpret_cast<void **>(&indexBuffer)); pMesh->LockVertexBuffer(0, reinterpret_cast<void **>(&vertexBuffer)); for(int i = 0; i < nodes.size(); i++) { auto face = nodes[i]; for(int j = 0; j < 3; j++) { D3DVERTEX &vert = vertexBuffer[3 * i + j]; vert.p.x = face.triangle[j].x; vert.p.y = face.triangle[j].y; vert.p.z = face.triangle[j].z; indexBuffer[3 * i + j] = 3 * i + j; pAdjacency[3 * i + j] = (face.adjacency[j] == 0xffff) ? 0xffffffffUL : face.adjacency[j]; } } //D3DXWeldVertices(pMesh, D3DXWELDEPSILONS_WELDALL, nullptr, pAdjacency, nullptr, nullptr, nullptr); //pMesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_IGNOREVERTS | D3DXMESHOPT_STRIPREORDER, newAdjacency, pAdjacency, nullptr, nullptr); delete[] pAdjacency; HRESULT hr = D3DXComputeNormals(pMesh, nullptr); D3DXMATERIAL *m_pMaterials = nullptr; DWORD m_dwNumMaterials = 0; hr = D3DXSaveMeshToX("NavMesh.x", pMesh, nullptr, m_pMaterials, nullptr, m_dwNumMaterials, D3DXF_FILEFORMAT_BINARY); pMesh->UnlockVertexBuffer(); pMesh->UnlockIndexBuffer(); return S_OK; }
/** * Exports all geometry into a D3D .x file into the current working folder. * @param Filename Desired filename (may include path) * @param bShow Whether the D3D .x file viewer should be invoked. If shown, we'll block until it has been closed. */ void F3DVisualizer::Export( const TCHAR* Filename, bool bShow/*=false*/ ) { ID3DXMesh* Mesh; Mesh = NULL; int32 NumPrimitives = NumTriangles() + NumLines()*2; int32 NumVertices = NumTriangles()*3 + NumLines()*4; HRESULT Result = D3DXCreateMeshFVF( NumPrimitives, NumVertices, D3DXMESH_32BIT, D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_SPECULAR, D3D->D3DDevice, &Mesh ); void* VertexBuffer = NULL; void* IndexBuffer = NULL; Result = Mesh->LockVertexBuffer(D3DLOCK_DISCARD, &VertexBuffer); Result = Mesh->LockIndexBuffer(D3DLOCK_DISCARD, &IndexBuffer); D3DXVertex* Vertices = (D3DXVertex*)VertexBuffer; uint32* Indices = (uint32*) IndexBuffer; int32 NumVerticesStored = 0; int32 NumIndicesStored = 0; // Add the triangles to the vertexbuffer and indexbuffer. for ( int32 TriangleIndex=0; TriangleIndex < NumTriangles(); ++TriangleIndex ) { const FVector4& P1 = Triangles[TriangleIndex].Vertices[0]; const FVector4& P2 = Triangles[TriangleIndex].Vertices[1]; const FVector4& P3 = Triangles[TriangleIndex].Vertices[2]; const FColor& Color = Triangles[TriangleIndex].Color; Vertices[NumVerticesStored+0].Pos[0] = P1[0]; Vertices[NumVerticesStored+0].Pos[1] = P1[1]; Vertices[NumVerticesStored+0].Pos[2] = P1[2]; Vertices[NumVerticesStored+0].Color1 = Color.DWColor(); Vertices[NumVerticesStored+0].Color2 = 0; Vertices[NumVerticesStored+1].Pos[0] = P2[0]; Vertices[NumVerticesStored+1].Pos[1] = P2[1]; Vertices[NumVerticesStored+1].Pos[2] = P2[2]; Vertices[NumVerticesStored+1].Color1 = Color.DWColor(); Vertices[NumVerticesStored+1].Color2 = 0; Vertices[NumVerticesStored+2].Pos[0] = P3[0]; Vertices[NumVerticesStored+2].Pos[1] = P3[1]; Vertices[NumVerticesStored+2].Pos[2] = P3[2]; Vertices[NumVerticesStored+2].Color1 = Color.DWColor(); Vertices[NumVerticesStored+2].Color2 = 0; // Reverse triangle winding order for the .x file. Indices[NumIndicesStored+0] = NumVerticesStored + 0; Indices[NumIndicesStored+1] = NumVerticesStored + 2; Indices[NumIndicesStored+2] = NumVerticesStored + 1; NumVerticesStored += 3; NumIndicesStored += 3; } // Add the lines to the vertexbuffer and indexbuffer. for ( int32 LineIndex=0; LineIndex < NumLines(); ++LineIndex ) { const FVector4& P1 = Lines[LineIndex].Vertices[0]; const FVector4& P2 = Lines[LineIndex].Vertices[1]; const FColor& Color = Lines[LineIndex].Color; Vertices[NumVerticesStored+0].Pos[0] = P1[0]; Vertices[NumVerticesStored+0].Pos[1] = P1[1] - 5.0f; Vertices[NumVerticesStored+0].Pos[2] = P1[2]; Vertices[NumVerticesStored+0].Color1 = 0; Vertices[NumVerticesStored+0].Color2 = Color.DWColor(); Vertices[NumVerticesStored+1].Pos[0] = P1[0]; Vertices[NumVerticesStored+1].Pos[1] = P1[1] + 5.0f; Vertices[NumVerticesStored+1].Pos[2] = P1[2]; Vertices[NumVerticesStored+1].Color1 = 0; Vertices[NumVerticesStored+1].Color2 = Color.DWColor(); Vertices[NumVerticesStored+2].Pos[0] = P2[0]; Vertices[NumVerticesStored+2].Pos[1] = P2[1] - 5.0f; Vertices[NumVerticesStored+2].Pos[2] = P2[2]; Vertices[NumVerticesStored+2].Color1 = 0; Vertices[NumVerticesStored+2].Color2 = Color.DWColor(); Vertices[NumVerticesStored+3].Pos[0] = P2[0]; Vertices[NumVerticesStored+3].Pos[1] = P2[1] + 5.0f; Vertices[NumVerticesStored+3].Pos[2] = P2[2]; Vertices[NumVerticesStored+3].Color1 = 0; Vertices[NumVerticesStored+3].Color2 = Color.DWColor(); Indices[NumIndicesStored+0] = NumVerticesStored+0; Indices[NumIndicesStored+1] = NumVerticesStored+2; Indices[NumIndicesStored+2] = NumVerticesStored+1; Indices[NumIndicesStored+3] = NumVerticesStored+2; Indices[NumIndicesStored+4] = NumVerticesStored+3; Indices[NumIndicesStored+5] = NumVerticesStored+1; NumVerticesStored += 4; NumIndicesStored += 6; } Mesh->UnlockVertexBuffer(); Mesh->UnlockIndexBuffer(); Result = D3DXComputeNormals( Mesh, NULL ); D3DXMATERIAL MeshMaterial; MeshMaterial.MatD3D.Ambient.r = 0.1f; MeshMaterial.MatD3D.Ambient.g = 0.1f; MeshMaterial.MatD3D.Ambient.b = 0.1f; MeshMaterial.MatD3D.Ambient.a = 0.0f; MeshMaterial.MatD3D.Diffuse.r = 1.0f; MeshMaterial.MatD3D.Diffuse.g = 1.0f; MeshMaterial.MatD3D.Diffuse.b = 1.0f; MeshMaterial.MatD3D.Diffuse.a = 1.0f; MeshMaterial.MatD3D.Emissive.r = 1.0f; MeshMaterial.MatD3D.Emissive.g = 1.0f; MeshMaterial.MatD3D.Emissive.b = 1.0f; MeshMaterial.MatD3D.Emissive.a = 1.0f; MeshMaterial.MatD3D.Specular.r = 1.0f; MeshMaterial.MatD3D.Specular.g = 1.0f; MeshMaterial.MatD3D.Specular.b = 1.0f; MeshMaterial.MatD3D.Specular.a = 1.0f; MeshMaterial.MatD3D.Power = 16.0f; MeshMaterial.pTextureFilename = NULL; D3DXEFFECTINSTANCE EffectInstance; EffectInstance.pEffectFilename = "D3DExport.fx"; EffectInstance.NumDefaults = 0; EffectInstance.pDefaults = NULL; // Write out the .x file. D3DXSaveMeshToX( Filename, Mesh, NULL, &MeshMaterial, &EffectInstance, 1, D3DXF_FILEFORMAT_BINARY ); Mesh->Release(); // Write out the .fx file, if it doesn't always exist. HANDLE ShaderFile = CreateFile( TEXT("D3DExport.fx"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (ShaderFile != INVALID_HANDLE_VALUE) { ::DWORD BytesWritten; WriteFile(ShaderFile, ShaderFxFile, (uint32)FCStringAnsi::Strlen(ShaderFxFile), &BytesWritten, NULL); CloseHandle( ShaderFile ); } // If specified, run the default viewer for .x files and block until it's closed. if ( bShow ) { system( TCHAR_TO_ANSI(Filename) ); } }
//----------------------------------------------------------------------------- // Desc: 在这里是调用了成员函数 GenerateGameSkinMesh(pMeshContainer); // 是在这里加载了蒙皮信息 //----------------------------------------------------------------------------- HRESULT DexAllocateHierarchy::CreateMeshContainer(LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer) { HRESULT hr; stDexMeshContainerEx *pMeshContainer = NULL; LPDIRECT3DDEVICE9 device = NULL; UINT NumFaces; UINT iMaterial; UINT iBone, cBones; LPD3DXMESH pMesh = NULL; *ppNewMeshContainer = NULL; // this sample does not handle patch meshes, so fail when one is found if (pMeshData->Type != D3DXMESHTYPE_MESH) { hr = E_FAIL; return hr; } // get the pMesh interface pointer out of the mesh data structure pMesh = pMeshData->pMesh; pMesh->GetDevice( &device ); // this sample does not FVF compatible meshes, so fail when one is found if (pMesh->GetFVF() == 0) { hr = E_FAIL; return hr; } // allocate the overloaded structure to return as a D3DXMESHCONTAINER pMeshContainer = new stDexMeshContainerEx; if (pMeshContainer == NULL) { hr = E_OUTOFMEMORY; return hr; } memset(pMeshContainer, 0, sizeof(stDexMeshContainerEx)); // make sure and copy the name. All memory as input belongs to caller, interfaces can be addref'd though hr = AllocateName(Name, &pMeshContainer->Name); if (FAILED(hr)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } NumFaces = pMesh->GetNumFaces(); // if no normals are in the mesh, add them if (!(pMesh->GetFVF() & D3DFVF_NORMAL)) { pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; // clone the mesh to make room for the normals hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, device, &pMeshContainer->MeshData.pMesh ); if (FAILED(hr)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } // get the new pMesh pointer back out of the mesh container to use // NOTE: we do not release pMesh because we do not have a reference to it yet pMesh = pMeshContainer->MeshData.pMesh; // now generate the normals for the pmesh D3DXComputeNormals( pMesh, NULL ); } else // if no normals, just add a reference to the mesh for the mesh container { pMeshContainer->MeshData.pMesh = pMesh; pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; pMesh->AddRef(); } // allocate memory to contain the material information. This sample uses // the D3D9 materials and texture names instead of the EffectInstance style materials pMeshContainer->NumMaterials = max(1, NumMaterials); pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; pMeshContainer->pAdjacency = new DWORD[NumFaces*3]; if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL)) { hr = E_OUTOFMEMORY; if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3); memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials); // if materials provided, copy them if (NumMaterials > 0) { memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials); for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++) { if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL) { //TCHAR file[1000]; //FindMediaFile(file,pMeshContainer->pMaterials[iMaterial].pTextureFilename); // 根据纹理的文件名创建纹理资源,如果创建失败,纹理指针必须赋成NULL // MessageNULL(file); //D3DXCreateTextureFromFileEx(device, file, // D3DX_DEFAULT_NONPOW2, // D3DX_DEFAULT_NONPOW2, // D3DX_FROM_FILE, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, // D3DX_FILTER_NONE, D3DX_FILTER_NONE, D3DCOLOR_XRGB(0,0,0), NULL, NULL, // &pMeshContainer->ppTextures[iMaterial]); string texname = "model/"; //轉到model文件夾中去找紋理 texname += pMeshContainer->pMaterials[iMaterial].pTextureFilename; if( FAILED( D3DXCreateTextureFromFile( device, texname.c_str(), &pMeshContainer->ppTextures[iMaterial] ) ) ) { getLog()->BeginLog(); getLog()->Log(log_allert, "load model texture %s failed! \n", texname.c_str()); pMeshContainer->ppTextures[iMaterial] = NULL; getLog()->EndLog(); } // don't remember a pointer into the dynamic memory, just forget the name after loading pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL; } } } else // if no materials provided, use a default one { pMeshContainer->pMaterials[0].pTextureFilename = NULL; memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9)); pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse; } // if there is skinning information, save off the required data and then setup for HW skinning if (pSkinInfo != NULL) { // first save off the SkinInfo and original mesh data pMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); pMeshContainer->pOrigMesh = pMesh; pMesh->AddRef(); // Will need an array of offset matrices to move the vertices from the figure space to the bone's space cBones = pSkinInfo->GetNumBones(); pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones]; if (pMeshContainer->pBoneOffsetMatrices == NULL) { hr = E_OUTOFMEMORY; if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } // get each of the bone offset matrices so that we don't need to get them later for (iBone = 0; iBone < cBones; iBone++) { pMeshContainer->pBoneOffsetMatrices[iBone] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone)); } // GenerateGameSkinMesh will take the general skinning information and transform it to a HW friendly version hr = GenerateGameSkinMesh(device, pMeshContainer ); if (FAILED(hr)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } } *ppNewMeshContainer = pMeshContainer; pMeshContainer = NULL; // call Destroy function to properly clean up the memory allocated if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; }
Mesh::Mesh(const std::string & strNombre,LPDIRECT3DDEVICE9 pd3dDevice) { m_strNombre=strNombre; // Carga el objeto del archivo especificado. if( FAILED( D3DXLoadMeshFromX( strNombre.c_str(), D3DXMESH_SYSTEMMEM, pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { MessageBox(NULL, "No se puede encontrar el archivo .x", "Error al cargar Mesh", MB_OK); } // Se extraen los materiales y texturas del objeto. D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; for( DWORD i=0; i<g_dwNumMaterials; i++ ) { // Copia el material. g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D; // Establece el color difuso del material. g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse; g_pMeshTextures[i] = NULL; if( d3dxMaterials[i].pTextureFilename != NULL && lstrlen(d3dxMaterials[i].pTextureFilename) > 0 ) { // Se crea la textura if( FAILED(D3DXCreateTextureFromFile( pd3dDevice, d3dxMaterials[i].pTextureFilename, &g_pMeshTextures[i] ) ) ) { MessageBox(NULL, "No se puede hallar el archivo de textura.", "Error al cargar textura", MB_OK); } } } // Se libera el buffer. pD3DXMtrlBuffer->Release(); // Clonar el mesh para insertarle en el FVF las normales y poder calcularlas // para su uso en la iluminacion. LPD3DXMESH lpTempMesh = NULL; g_pMesh->CloneMeshFVF(0, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE |D3DFVF_TEX1 , pd3dDevice, &lpTempMesh); D3DXComputeNormals( lpTempMesh,NULL); g_pMesh=lpTempMesh; }
HRESULT XFileCreator::CreateMesh(std::vector<Vertex> vertices, std::vector<Face> faces) { HRESULT hr; DWORD numFaces = faces.size(); DWORD numVertices = vertices.size(); PD(L"number of vertices: ", numVertices); PD(L"number of faces: ", numFaces); D3DVERTEXELEMENT9 localVertDecl[MAX_FVF_DECL_SIZE] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, D3DDECL_END() }; hr = D3DXCreateMesh(numFaces, numVertices, D3DXMESH_MANAGED | D3DXMESH_32BIT, localVertDecl, mDevice, &mMesh); PD(hr, L"create mesh"); if(FAILED(hr)) return hr; LOCAL_VERTEX *pVertices = NULL; hr = mMesh->LockVertexBuffer(0, (void**)&pVertices); PD(hr, L"lock vertex buffer"); if(FAILED(hr)) return hr; for ( DWORD i = 0; i < numVertices; ++i ) { pVertices[i].pos = D3DXVECTOR3(vertices[i].pos.x, vertices[i].pos.y, vertices[i].pos.z); } hr = mMesh->UnlockVertexBuffer(); PD(hr, L"unlock vertex buffer"); if(FAILED(hr)) return hr; DWORD* pIndices = NULL; hr = mMesh->LockIndexBuffer(0, (void**)&pIndices); PD(hr, L"lock index buffer"); if(FAILED(hr)) return hr; for ( DWORD i = 0; i < numFaces; i++ ) { pIndices[3 * i] = faces[i].vertices[0]; pIndices[3 * i + 1] = faces[i].vertices[1]; pIndices[3 * i + 2] = faces[i].vertices[2]; } hr = mMesh->UnlockIndexBuffer(); PD(hr, L"unlock index buffer"); if(FAILED(hr)) return hr; DWORD* pAdjacency = new DWORD[numFaces * 3]; hr = mMesh->GenerateAdjacency(1e-6f, pAdjacency); PD(hr, L"generate adjacency"); if(FAILED(hr)) return hr; hr = D3DXComputeNormals(mMesh, pAdjacency); PD(hr, L"compute normals"); if(FAILED(hr)) return hr; delete [] pAdjacency; return D3D_OK; }
HRESULT PATCH::CreateMesh(HEIGHTMAP &hm, RECT source, IDirect3DDevice9* Dev, int index) { if(m_pMesh != NULL) { m_pMesh->Release(); m_pMesh = NULL; } try { m_pDevice = Dev; int width = source.right - source.left; int height = source.bottom - source.top; int nrVert = (width + 1) * (height + 1); int nrTri = width * height * 2; if(FAILED(D3DXCreateMeshFVF(nrTri, nrVert, D3DXMESH_MANAGED, TERRAINVertex::FVF, m_pDevice, &m_pMesh))) { debug.Print("Couldn't create mesh for PATCH"); return E_FAIL; } //Create vertices TERRAINVertex* ver = 0; m_pMesh->LockVertexBuffer(0,(void**)&ver); for(int z=source.top, z0 = 0;z<=source.bottom;z++, z0++) for(int x=source.left, x0 = 0;x<=source.right;x++, x0++) { //Calculate vertex color float prc = hm.m_pHeightMap[x + z * hm.m_size.x] / hm.m_maxHeight; int red = (int)(255 * prc); int green = (int)(255 * (1.0f - prc)); D3DCOLOR col; if(index % 2 == 0) //Invert color depending on what patch it is... col = D3DCOLOR_ARGB(255, red, green, 0); else col = D3DCOLOR_ARGB(255, green, red, 0); //Extract height (and position) from heightmap D3DXVECTOR3 pos = D3DXVECTOR3((float)x, hm.m_pHeightMap[x + z * hm.m_size.x], (float)-z); //Set new vertex ver[z0 * (width + 1) + x0] = TERRAINVertex(pos, col); } m_pMesh->UnlockVertexBuffer(); //Calculate Indices WORD* ind = 0; m_pMesh->LockIndexBuffer(0,(void**)&ind); int index = 0; for(int z=source.top, z0 = 0;z<source.bottom;z++, z0++) for(int x=source.left, x0 = 0;x<source.right;x++, x0++) { //Triangle 1 ind[index++] = z0 * (width + 1) + x0; ind[index++] = z0 * (width + 1) + x0 + 1; ind[index++] = (z0+1) * (width + 1) + x0; //Triangle 2 ind[index++] = (z0+1) * (width + 1) + x0; ind[index++] = z0 * (width + 1) + x0 + 1; ind[index++] = (z0+1) * (width + 1) + x0 + 1; } m_pMesh->UnlockIndexBuffer(); //Set Attributes DWORD *att = 0; m_pMesh->LockAttributeBuffer(0,&att); memset(att, 0, sizeof(DWORD)*nrTri); m_pMesh->UnlockAttributeBuffer(); //Compute normals D3DXComputeNormals(m_pMesh, NULL); } catch(...) { debug.Print("Error in PATCH::CreateMesh()"); return E_FAIL; } return S_OK; }
HRESULT KG3DMeshBone::_CreateMesh() { HRESULT hResult = E_FAIL; HRESULT hRetCode = E_FAIL; DWORD dwNumFaces = (DWORD)m_vecSubMeshInfo.size() * 8; DWORD dwNumVertices = (DWORD)m_vecSubMeshInfo.size() * 6; VFormat::FACES_NORMAL_DIFFUSE_TEXTURE0* pVBuffer = NULL; WORD* pIBuffer = NULL; DWORD* pABuffer = NULL; hRetCode = D3DXCreateMeshFVF( dwNumFaces, dwNumVertices, D3DXMESH_MANAGED, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE, g_pd3dDevice, &m_pSysMesh ); KG_COM_PROCESS_ERROR(hRetCode); // vertex hRetCode = m_pSysMesh->LockVertexBuffer(0, (void**)&pVBuffer); KG_COM_PROCESS_ERROR(hRetCode); for (DWORD i = 0; i < m_vecSubMeshInfo.size(); i++) { pVBuffer[i * 6].p = m_vecSubMeshInfo[i].vPosition[0]; pVBuffer[i * 6].diffuse = 0xFFFFFFFF; pVBuffer[i * 6 + 1].p = m_vecSubMeshInfo[i].vPosition[1]; pVBuffer[i * 6 + 1].diffuse = 0xFFFF0000; pVBuffer[i * 6 + 2].p = m_vecSubMeshInfo[i].vPosition[2]; pVBuffer[i * 6 + 2].diffuse = 0xFF0000FF; pVBuffer[i * 6 + 3].p = m_vecSubMeshInfo[i].vPosition[3]; pVBuffer[i * 6 + 3].diffuse = 0xFF00FF00; pVBuffer[i * 6 + 4].p = m_vecSubMeshInfo[i].vPosition[4]; pVBuffer[i * 6 + 4].diffuse = 0xFFFFFF00; pVBuffer[i * 6 + 5].p = m_vecSubMeshInfo[i].vPosition[5]; pVBuffer[i * 6 + 5].diffuse = 0xFFFFFFFF; } hRetCode = m_pSysMesh->UnlockVertexBuffer(); KG_COM_PROCESS_ERROR(hRetCode); // index hRetCode = m_pSysMesh->LockIndexBuffer(0, (void**)&pIBuffer); KG_COM_PROCESS_ERROR(hRetCode); for (DWORD i = 0; i < m_vecSubMeshInfo.size(); i++) { for (DWORD j = 0; j < 24; j++) { pIBuffer[i * 24 + j] = (WORD)(m_vecSubMeshInfo[i].dwIndex[j] + 6 * i); } } hRetCode = m_pSysMesh->UnlockIndexBuffer(); KG_COM_PROCESS_ERROR(hRetCode); // index hRetCode = m_pSysMesh->LockAttributeBuffer(0, (DWORD**)&pABuffer); KG_COM_PROCESS_ERROR(hRetCode); for (DWORD i = 0; i < m_vecSubMeshInfo.size(); i++) { for (DWORD j = 0; j < 8; j++) { pABuffer[i * 8 + j] = i; } } hRetCode = m_pSysMesh->UnlockAttributeBuffer(); KG_COM_PROCESS_ERROR(hRetCode); D3DXComputeNormals(m_pSysMesh, NULL); hResult = S_OK; Exit0: return hResult; }
//----------------------------------------------------------------------------- // Name: CDXUTMesh::SetVertexDecl // Desc: Convert the mesh to the format specified by the given vertex // declarations. //----------------------------------------------------------------------------- HRESULT CDXUTMesh::SetVertexDecl( LPDIRECT3DDEVICE9 pd3dDevice, const D3DVERTEXELEMENT9 *pDecl ) { LPD3DXMESH pTempSysMemMesh = NULL; LPD3DXMESH pTempLocalMesh = NULL; if( m_pSysMemMesh ) { if( FAILED( m_pSysMemMesh->CloneMesh( m_pSysMemMesh->GetOptions(), pDecl, pd3dDevice, &pTempSysMemMesh ) ) ) return E_FAIL; } if( m_pLocalMesh ) { if( FAILED( m_pLocalMesh->CloneMesh( m_pLocalMesh->GetOptions(), pDecl, pd3dDevice, &pTempLocalMesh ) ) ) { SAFE_RELEASE( pTempSysMemMesh ); return E_FAIL; } } // Check if the old declaration contains a normal. bool bHadNormal = false; D3DVERTEXELEMENT9 aOldDecl[MAX_FVF_DECL_SIZE]; if( m_pSysMemMesh && SUCCEEDED( m_pSysMemMesh->GetDeclaration( aOldDecl ) ) ) { for( UINT index = 0; index < D3DXGetDeclLength( aOldDecl ); ++index ) if( aOldDecl[index].Usage == D3DDECLUSAGE_NORMAL ) { bHadNormal = true; break; } } // Check if the new declaration contains a normal. bool bHaveNormalNow = false; D3DVERTEXELEMENT9 aNewDecl[MAX_FVF_DECL_SIZE]; if( pTempSysMemMesh && SUCCEEDED( pTempSysMemMesh->GetDeclaration( aNewDecl ) ) ) { for( UINT index = 0; index < D3DXGetDeclLength( aNewDecl ); ++index ) if( aNewDecl[index].Usage == D3DDECLUSAGE_NORMAL ) { bHaveNormalNow = true; break; } } SAFE_RELEASE( m_pSysMemMesh ); SAFE_RELEASE( m_pLocalMesh ); if( pTempSysMemMesh ) { m_pSysMemMesh = pTempSysMemMesh; if( !bHadNormal && bHaveNormalNow ) { // Compute normals in case the meshes have them D3DXComputeNormals( m_pSysMemMesh, NULL ); } } if( pTempLocalMesh ) { m_pLocalMesh = pTempLocalMesh; if( !bHadNormal && bHaveNormalNow ) { // Compute normals in case the meshes have them D3DXComputeNormals( m_pLocalMesh, NULL ); } } return S_OK; }
MeshContainer* XFileLoader::CreateMeshContainer() { HRESULT hr; MeshContainer* meshContainer = NULL; Graphics* graphics = Graphics::GetInstance(); IDirect3DDevice9Ptr pD3DDevice = graphics->GetDirect3DDevice(); if( !(m_pD3DMesh->GetFVF() & D3DFVF_NORMAL) ) { LPD3DXMESH tmpMesh = NULL; // 柔軟な頂点フォーマット (FVF) コードを使ってメッシュのコピーを作成する hr = m_pD3DMesh->CloneMeshFVF( m_pD3DMesh->GetOptions(), m_pD3DMesh->GetFVF() | D3DFVF_NORMAL, pD3DDevice, &tmpMesh); // ←ここにコピー if(FAILED(hr)) { goto exit; } // メッシュに含まれる各頂点の法線を計算して、設定する //D3DXComputeNormals( tmpMesh, reinterpret_cast<DWORD*>(pAdjacencyBuf->GetBufferPointer()) ); D3DXComputeNormals( tmpMesh, NULL ); m_pD3DMesh->Release(); m_pD3DMesh = tmpMesh; } D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE]; hr = m_pD3DMesh->GetDeclaration(pDecl); if( FAILED(hr) ) { goto exit; } DWORD vertexNum = m_pD3DMesh->GetNumVertices(); DWORD faceNum = m_pD3DMesh->GetNumFaces(); DWORD attrNum = 0; m_pD3DMesh->GetAttributeTable(NULL, &attrNum); DWORD size = m_pD3DMesh->GetNumBytesPerVertex(); BYTE* pD3DVertice = NULL; m_pD3DMesh->LockVertexBuffer( 0,(LPVOID*)&pD3DVertice ); sVertex* vertices = new sVertex[vertexNum]; for( DWORD vertIdx = 0;vertIdx<vertexNum;vertIdx++ ) { sVertex* vertex = &vertices[vertIdx]; vertex->uv = D3DXVECTOR2(0.0f,0.0f); vertex->color = 0xFFFFFFFF; for( DWORD i=0;i<MAX_FVF_DECL_SIZE;i++ ) { D3DVERTEXELEMENT9& decl = pDecl[i]; if( decl.Stream==0xFF ) { break; } switch( decl.Usage ) { case D3DDECLUSAGE_POSITION: vertex->position = *(D3DXVECTOR3*)(pD3DVertice+vertIdx*size+decl.Offset); vertex->position = vertex->position * m_scale; break; case D3DDECLUSAGE_NORMAL: vertex->normal = *(D3DXVECTOR3*)(pD3DVertice+vertIdx*size+decl.Offset); break; case D3DDECLUSAGE_TEXCOORD: vertex->uv = *(D3DXVECTOR2*)(pD3DVertice+vertIdx*size+decl.Offset); break; case D3DDECLUSAGE_COLOR: vertex->color = *(DWORD*)(pD3DVertice+vertIdx*size+decl.Offset); break; } } } m_pD3DMesh->UnlockVertexBuffer(); LPDIRECT3DINDEXBUFFER9 pIndexBuffer = NULL; m_pD3DMesh->GetIndexBuffer( &pIndexBuffer ); D3DINDEXBUFFER_DESC desc; pIndexBuffer->GetDesc( &desc ); pIndexBuffer->Release(); DWORD* indices = new DWORD[faceNum*3]; if( desc.Format==D3DFMT_INDEX16 ) { WORD* pD3DIndices = NULL; m_pD3DMesh->LockIndexBuffer(0,(LPVOID*)&pD3DIndices ); for( DWORD i=0;i<faceNum*3;i++ ) { indices[i] = pD3DIndices[i]; } m_pD3DMesh->UnlockIndexBuffer(); } else { DWORD* pD3DIndices =NULL; m_pD3DMesh->LockIndexBuffer(0,(LPVOID*)&pD3DIndices ); memcpy( indices,pD3DIndices,sizeof(DWORD)*faceNum*3 ); m_pD3DMesh->UnlockIndexBuffer(); } D3DXATTRIBUTERANGE *attrList = new D3DXATTRIBUTERANGE[attrNum]; m_pD3DMesh->GetAttributeTable(attrList, &attrNum); meshContainer = new MeshContainer; meshContainer->pMesh = new Mesh; meshContainer->pMesh->Create( vertexNum,faceNum,attrNum ); meshContainer->pMesh->SetVertices( vertices ); meshContainer->pMesh->SetIndices( indices ); meshContainer->pMesh->SetAttributeRanges( attrList ); delete[] vertices; delete[] indices; delete[] attrList; meshContainer->materialNum = m_Materials; meshContainer->pMaterials = new sMaterial[m_Materials]; D3DXMATERIAL* pD3DMaterials = (D3DXMATERIAL*)m_pMaterialBuf->GetBufferPointer(); for( DWORD i=0;i<m_Materials;i++ ) { sMaterial* pMaterial = &meshContainer->pMaterials[i]; D3DXMATERIAL* pD3DMaterial = &pD3DMaterials[i]; pMaterial->colorDiffuse = pD3DMaterial->MatD3D.Diffuse; pMaterial->colorSpecular.r = pD3DMaterial->MatD3D.Specular.r; pMaterial->colorSpecular.g = pD3DMaterial->MatD3D.Specular.g; pMaterial->colorSpecular.b = pD3DMaterial->MatD3D.Specular.b; pMaterial->colorSpecular.a = 0.0f; pMaterial->colorAmbient.r = pD3DMaterial->MatD3D.Diffuse.r; pMaterial->colorAmbient.g = pD3DMaterial->MatD3D.Diffuse.g; pMaterial->colorAmbient.b = pD3DMaterial->MatD3D.Diffuse.b; pMaterial->colorAmbient.a = 0.0f; pMaterial->colorEmissive.r = pD3DMaterial->MatD3D.Emissive.r; pMaterial->colorEmissive.g = pD3DMaterial->MatD3D.Emissive.g; pMaterial->colorEmissive.b = pD3DMaterial->MatD3D.Emissive.b; pMaterial->colorEmissive.a = 0.0f; pMaterial->specularPower = pD3DMaterial->MatD3D.Power; TCHAR path[MAX_PATH]; _tcscpy_s( path,m_path.c_str() ); tstring texFileName; tstring sphereFileName; if( pD3DMaterial->pTextureFilename && strlen(pD3DMaterial->pTextureFilename)>0 ) { tstring filename = to_tstring(pD3DMaterial->pTextureFilename); tstring::size_type index = filename.find( _T("*") ); if( index != tstring::npos ) { sphereFileName = filename.substr( index+1 ); PathAppend( path,sphereFileName.c_str() ); sphereFileName = path; PathRemoveFileSpec( path ); texFileName = filename.erase( index ); PathAppend( path,texFileName.c_str() ); texFileName = path; PathRemoveFileSpec( path ); } else { texFileName = filename; PathAppend( path,texFileName.c_str() ); texFileName = path; PathRemoveFileSpec( path ); } tstring ext = PathFindExtension( texFileName.c_str() ); if( ext == _T(".sph" ) || ext == _T(".spa") ) { sphereFileName = texFileName; texFileName = _T(""); } } if( !texFileName.empty() ) { TexturePtr pTex = ResourceManager::GetInstance().GetResource<Texture>( texFileName ); if( !pTex ) { pTex = TexturePtr(new Texture); if( pTex->CreateFromFile( texFileName ) ) { ResourceManager::GetInstance().AddResource( texFileName,pTex ); } else { pTex.reset(); } } if( pTex ) { pMaterial->textureDiffuse = pTex; } } if( !sphereFileName.empty() ) { TexturePtr pTex = ResourceManager::GetInstance().GetResource<Texture>( sphereFileName ); if( !pTex ) { pTex = TexturePtr(new Texture); if( pTex->CreateFromFile( sphereFileName ) ) { ResourceManager::GetInstance().AddResource( sphereFileName,pTex ); } else { pTex.reset(); } } if( pTex ) { pMaterial->textureSphere = pTex; } tstring ext = PathFindExtension( sphereFileName.c_str() ); if( ext == _T(".sph" ) ) { pMaterial->spheremap = eSPHEREMAP_MUL; } else if( ext == _T(".spa") ) { pMaterial->spheremap = eSPHEREMAP_ADD; } } } exit: if( m_pMaterialBuf ) { m_pMaterialBuf->Release(); m_pMaterialBuf = NULL; } if( m_pEffectInstancesBuf ) { m_pEffectInstancesBuf->Release(); m_pEffectInstancesBuf = NULL; } if( m_pAdjacencyBuf ) { m_pAdjacencyBuf->Release(); m_pAdjacencyBuf = NULL; } if( m_pD3DMesh ) { m_pD3DMesh->Release(); m_pD3DMesh = NULL; } return meshContainer; }
//----------------------------------------------------------------------------- // Name: InitDeviceObjects() // Desc: Initialize scene objects. //----------------------------------------------------------------------------- HRESULT CMeshRender::InitDeviceObjects() { DWORD cVerticesPerMesh; // Load mesh LPD3DXBUFFER pAdjacencyBuffer = NULL; LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL; LPD3DXMESH pMesh = NULL; LPD3DXPMESH pPMesh = NULL; LPD3DXMESH pTempMesh; LPD3DXBUFFER pD3DXMtrlBuffer = NULL; void* pVertices; TCHAR strMediaPath[512]; HRESULT hr; DWORD dw32BitFlag; DWORD cVerticesMin; DWORD cVerticesMax; DWORD iPMesh; D3DXWELDEPSILONS Epsilons; DWORD i; D3DXMATERIAL* d3dxMaterials; // Find the path to the mesh if( FAILED( DXUtil_FindMediaFileCb( strMediaPath, sizeof(strMediaPath), m_strMeshFilename ) ) ) return E_FAIL;//D3DAPPERR_MEDIANOTFOUND; // Load the mesh from the specified file if( FAILED( hr = D3DXLoadMeshFromX( strMediaPath, D3DXMESH_MANAGED, m_pd3dDevice, &pAdjacencyBuffer, &pD3DXMtrlBuffer, NULL, &m_dwNumMaterials, &pMesh ) ) ) { // hide error so that device changes will not cause exit, shows blank screen instead goto End; } dw32BitFlag = (pMesh->GetOptions() & D3DXMESH_32BIT); // perform simple cleansing operations on mesh if( FAILED( hr = D3DXCleanMesh( pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), &pTempMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL ) ) ) { m_dwNumMaterials = 0; goto End; } SAFE_RELEASE(pMesh); pMesh = pTempMesh; // Perform a weld to try and remove excess vertices like the model bigship1.x in the DX9.0 SDK (current model is fixed) // Weld the mesh using all epsilons of 0.0f. A small epsilon like 1e-6 works well too memset(&Epsilons, 0, sizeof(D3DXWELDEPSILONS)); if( FAILED( hr = D3DXWeldVertices( pMesh, 0, &Epsilons, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL ) ) ) { m_dwNumMaterials = 0; goto End; } // verify validity of mesh for simplification if( FAILED( hr = D3DXValidMesh( pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL ) ) ) { m_dwNumMaterials = 0; goto End; } // Allocate a material/texture arrays d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); m_mtrlMeshMaterials = new D3DMATERIAL9[m_dwNumMaterials]; m_pMeshTextures = new LPDIRECT3DTEXTURE9[m_dwNumMaterials]; // Copy the materials and load the textures for( i=0; i<m_dwNumMaterials; i++ ) { m_mtrlMeshMaterials[i] = d3dxMaterials[i].MatD3D; m_mtrlMeshMaterials[i].Ambient = m_mtrlMeshMaterials[i].Diffuse; // Find the path to the texture and create that texture DXUtil_FindMediaFileCb( strMediaPath, sizeof(strMediaPath), d3dxMaterials[i].pTextureFilename ); if( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, strMediaPath, &m_pMeshTextures[i] ) ) ) m_pMeshTextures[i] = NULL; } pD3DXMtrlBuffer->Release(); pD3DXMtrlBuffer = NULL; // Lock the vertex buffer, to generate a simple bounding sphere hr = pMesh->GetVertexBuffer( &pVertexBuffer ); if( FAILED(hr) ) goto End; hr = pVertexBuffer->Lock( 0, 0, &pVertices, D3DLOCK_NOSYSLOCK ); if( FAILED(hr) ) goto End; hr = D3DXComputeBoundingSphere( (D3DXVECTOR3*)pVertices, pMesh->GetNumVertices(), D3DXGetFVFVertexSize(pMesh->GetFVF()), &m_vObjectCenter, &m_fObjectRadius ); pVertexBuffer->Unlock(); pVertexBuffer->Release(); if( FAILED(hr) || m_dwNumMaterials == 0 ) goto End; if ( !(pMesh->GetFVF() & D3DFVF_NORMAL) ) { hr = pMesh->CloneMeshFVF( dw32BitFlag|D3DXMESH_MANAGED, pMesh->GetFVF() | D3DFVF_NORMAL, m_pd3dDevice, &pTempMesh ); if (FAILED(hr)) goto End; D3DXComputeNormals( pTempMesh, NULL ); pMesh->Release(); pMesh = pTempMesh; } hr = D3DXGeneratePMesh( pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, 1, D3DXMESHSIMP_VERTEX, &pPMesh); if( FAILED(hr) ) goto End; cVerticesMin = pPMesh->GetMinVertices(); cVerticesMax = pPMesh->GetMaxVertices(); cVerticesPerMesh = (cVerticesMax - cVerticesMin) / 10; m_cPMeshes = max(1, (DWORD)ceil((cVerticesMax - cVerticesMin) / (float)cVerticesPerMesh)); m_pPMeshes = new LPD3DXPMESH[m_cPMeshes]; if (m_pPMeshes == NULL) { hr = E_OUTOFMEMORY; goto End; } memset(m_pPMeshes, 0, sizeof(LPD3DXPMESH) * m_cPMeshes); // clone full size pmesh hr = pPMesh->ClonePMeshFVF( D3DXMESH_MANAGED | D3DXMESH_VB_SHARE, pPMesh->GetFVF(), m_pd3dDevice, &m_pPMeshFull ); if (FAILED(hr)) goto End; // clone all the separate pmeshes for (iPMesh = 0; iPMesh < m_cPMeshes; iPMesh++) { hr = pPMesh->ClonePMeshFVF( D3DXMESH_MANAGED | D3DXMESH_VB_SHARE, pPMesh->GetFVF(), m_pd3dDevice, &m_pPMeshes[iPMesh] ); if (FAILED(hr)) goto End; // trim to appropriate space hr = m_pPMeshes[iPMesh]->TrimByVertices(cVerticesMin + cVerticesPerMesh * iPMesh, cVerticesMin + cVerticesPerMesh * (iPMesh+1), NULL, NULL); if (FAILED(hr)) goto End; hr = m_pPMeshes[iPMesh]->OptimizeBaseLOD(D3DXMESHOPT_VERTEXCACHE, NULL); if (FAILED(hr)) goto End; } // set current to be maximum number of vertices m_iPMeshCur = m_cPMeshes - 1; hr = m_pPMeshes[m_iPMeshCur]->SetNumVertices(cVerticesMax); if (FAILED(hr)) goto End; hr = m_pPMeshFull->SetNumVertices(cVerticesMax); if (FAILED(hr)) goto End; End: SAFE_RELEASE( pAdjacencyBuffer ); SAFE_RELEASE( pD3DXMtrlBuffer ); SAFE_RELEASE( pMesh ); SAFE_RELEASE( pPMesh ); if (FAILED(hr)) { for (iPMesh = 0; iPMesh < m_cPMeshes; iPMesh++) { SAFE_RELEASE( m_pPMeshes[iPMesh] ); } delete []m_pPMeshes; m_cPMeshes = 0; m_pPMeshes = NULL; SAFE_RELEASE( m_pPMeshFull ) } return hr; }
void Terrain::buildGeometry() { //=============================================================== // Create one large mesh for the grid in system memory. DWORD numTris = (mVertRows-1)*(mVertCols-1)*2; DWORD numVerts = mVertRows*mVertCols; ID3DXMesh* mesh = 0; D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; UINT numElems = 0; HR(VertexPNT::Decl->GetDeclaration(elems, &numElems)); HR(D3DXCreateMesh(numTris, numVerts, D3DXMESH_SYSTEMMEM|D3DXMESH_32BIT, elems, gd3dDevice, &mesh)); //=============================================================== // Write the grid vertices and triangles to the mesh. VertexPNT* v = 0; HR(mesh->LockVertexBuffer(0, (void**)&v)); std::vector<D3DXVECTOR3> verts; std::vector<DWORD> indices; GenTriGrid(mVertRows, mVertCols, mDX, mDZ, D3DXVECTOR3(0.0f, 0.0f, 0.0f), verts, indices); float w = mWidth; float d = mDepth; for(UINT i = 0; i < mesh->GetNumVertices(); ++i) { // We store the grid vertices in a linear array, but we can // convert the linear array index to an (r, c) matrix index. int r = i / mVertCols; int c = i % mVertCols; v[i].pos = verts[i]; v[i].pos.y = mHeightmap(r, c); v[i].tex0.x = (v[i].pos.x + (0.5f*w)) / w; v[i].tex0.y = (v[i].pos.z - (0.5f*d)) / -d; } // Write triangle data so we can compute normals. DWORD* indexBuffPtr = 0; HR(mesh->LockIndexBuffer(0, (void**)&indexBuffPtr)); for(UINT i = 0; i < mesh->GetNumFaces(); ++i) { indexBuffPtr[i*3+0] = indices[i*3+0]; indexBuffPtr[i*3+1] = indices[i*3+1]; indexBuffPtr[i*3+2] = indices[i*3+2]; } HR(mesh->UnlockIndexBuffer()); // Compute Vertex Normals. HR(D3DXComputeNormals(mesh, 0)); //=============================================================== // Now break the grid up into subgrid meshes. // Find out the number of subgrids we'll have. For example, if // m = 513, n = 257, SUBGRID_VERT_ROWS = SUBGRID_VERT_COLS = 33, // then subGridRows = 512/32 = 16 and sibGridCols = 256/32 = 8. int subGridRows = (mVertRows-1) / (SubGrid::NUM_ROWS-1); int subGridCols = (mVertCols-1) / (SubGrid::NUM_COLS-1); for(int r = 0; r < subGridRows; ++r) { for(int c = 0; c < subGridCols; ++c) { // Rectangle that indicates (via matrix indices ij) the // portion of global grid vertices to use for this subgrid. RECT R = { c * (SubGrid::NUM_COLS-1), r * (SubGrid::NUM_ROWS-1), (c+1) * (SubGrid::NUM_COLS-1), (r+1) * (SubGrid::NUM_ROWS-1) }; buildSubGridMesh(R, v); } } HR(mesh->UnlockVertexBuffer()); ReleaseCOM(mesh); // Done with global mesh. }
//**関数*************************************************************************** // メッシュ初期化 //********************************************************************************* bool CMesh::Initialize(LPCTSTR pszFName) { TCHAR szMsg[MAX_PATH + 32]; TCHAR szDir[_MAX_DIR]; TCHAR szCurrentDir[_MAX_PATH]; LPD3DXBUFFER pD3DXMtrlBuffer = NULL; // フォルダ名を抽出 _tsplitpath(pszFName, NULL, szDir, NULL, NULL); // Xファイルからメッシュデータを読み込む HRESULT hr = D3DXLoadMeshFromX(pszFName, D3DXMESH_SYSTEMMEM, CGraphics::GetDevice(), NULL, &pD3DXMtrlBuffer, NULL, &m_dwNumMaterial, &m_pD3DMesh); if (FAILED(hr)) { _stprintf(szMsg, _T("Xファイル(%s)の読み込みに失敗しました。"), pszFName); MessageBox(NULL, szMsg, NULL, MB_OK); return false; } // FVF形式を補正(頂点フォーマットを変換) LPD3DXMESH pMeshTmp; DWORD dwFVF = m_pD3DMesh->GetFVF(); if (dwFVF != FVF_BVERTEX) { hr = m_pD3DMesh->CloneMeshFVF(m_pD3DMesh->GetOptions(), FVF_BVERTEX, CGraphics::GetDevice(), &pMeshTmp); SAFE_RELEASE(m_pD3DMesh); if (FAILED(hr)) { SAFE_RELEASE(pD3DXMtrlBuffer); return false; } // 法線が無い場合は強制的に追加 if ((dwFVF & D3DFVF_NORMAL) == 0) { D3DXComputeNormals(pMeshTmp, NULL); } m_pD3DMesh = pMeshTmp; } // 接ベクトルがない場合は強制的に追加 D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE]; D3DVERTEXELEMENT9 End = D3DDECL_END(); int iElem; m_pD3DMesh->GetDeclaration(Declaration); BOOL bHasTangents = FALSE; for (iElem = 0; Declaration[iElem].Stream != End.Stream; iElem++) { if (Declaration[iElem].Usage == D3DDECLUSAGE_TANGENT) { bHasTangents = TRUE; break; } } // Update Mesh Semantics if changed if (!bHasTangents) { Declaration[iElem].Stream = 0; Declaration[iElem].Offset = (WORD)m_pD3DMesh->GetNumBytesPerVertex(); Declaration[iElem].Type = D3DDECLTYPE_FLOAT3; Declaration[iElem].Method = D3DDECLMETHOD_DEFAULT; Declaration[iElem].Usage = D3DDECLUSAGE_TANGENT; Declaration[iElem].UsageIndex = 0; Declaration[iElem+1] = End; LPD3DXMESH pTempMesh; hr = m_pD3DMesh->CloneMesh(D3DXMESH_MANAGED, Declaration, CGraphics::GetDevice() , &pTempMesh); if (SUCCEEDED(hr)) { SAFE_RELEASE(m_pD3DMesh); m_pD3DMesh = pTempMesh; //hr = D3DXComputeTangent(m_pMesh, 0, 0, D3DX_DEFAULT, TRUE, NULL); hr = D3DXComputeTangent(m_pD3DMesh , 0, 0, D3DX_DEFAULT, FALSE, NULL); } } // 属性テーブルを生成するための最適化 hr = m_pD3DMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &pMeshTmp); if (SUCCEEDED(hr)) { m_pD3DMesh->Release(); m_pD3DMesh = pMeshTmp; } else { SAFE_RELEASE(pD3DXMtrlBuffer); return false; } // 属性テーブル取得 hr = m_pD3DMesh->GetAttributeTable(NULL, &m_dwAttr); if (FAILED(hr)) { SAFE_RELEASE(pD3DXMtrlBuffer); SAFE_RELEASE(m_pD3DMesh); return false; } m_pAttr = new D3DXATTRIBUTERANGE[m_dwAttr]; hr = m_pD3DMesh->GetAttributeTable(m_pAttr, &m_dwAttr); // 頂点バッファ/インデックスバッファ固定 LPVOID pVtx; m_pD3DMesh->LockVertexBuffer(D3DLOCK_READONLY, &pVtx); LPVOID pIdx; m_pD3DMesh->LockIndexBuffer(D3DLOCK_READONLY, &pIdx); // 抽出場所の確保 m_dwVtx = m_pD3DMesh->GetNumVertices(); m_pVtx = new BVERTEX[m_dwVtx]; m_dwFace = m_pD3DMesh->GetNumFaces(); m_dwIdx = m_dwFace * 3; m_pIdx = new WORD[m_dwIdx]; m_pPiece = new PARTICLE[m_dwFace]; m_pPieceVtx = new BVERTEX[m_dwIdx]; // コピー CopyMemory(m_pVtx, pVtx, sizeof(BVERTEX) * m_dwVtx); CopyMemory(m_pIdx, pIdx, sizeof(WORD) * m_dwIdx); // 頂点バッファ/インデックスバッファ解放 m_pD3DMesh->UnlockVertexBuffer(); m_pD3DMesh->UnlockIndexBuffer(); // カレントディレクトリを変更 if (szDir[0]) { GetCurrentDirectory(_MAX_PATH, szCurrentDir); SetCurrentDirectory(szDir); } // マテリアル読み込み D3DXMATERIAL* pD3DMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); m_pMaterial = new D3DMATERIAL9[m_dwNumMaterial]; m_ppTexture = new LPDIRECT3DTEXTURE9[m_dwNumMaterial]; for (DWORD i = 0; i < m_dwNumMaterial; i++) { m_pMaterial[i] = pD3DMaterials[i].MatD3D; m_pMaterial[i].Ambient = m_pMaterial[i].Diffuse; m_ppTexture[i] = NULL; if (pD3DMaterials[i].pTextureFilename && pD3DMaterials[i].pTextureFilename[0]) { // テクスチャファイルを読み込む if (FAILED(D3DXCreateTextureFromFileA(CGraphics::GetDevice(), pD3DMaterials[i].pTextureFilename, &m_ppTexture[i]))) { _stprintf(szMsg, _T("テクスチャ(%hs)の読み込みに失敗しました。"), pD3DMaterials[i].pTextureFilename); MessageBox(NULL, szMsg, NULL, MB_OK); } } } // カレントディレクトリを元に戻す if (szDir[0]) SetCurrentDirectory(szCurrentDir); pD3DXMtrlBuffer->Release(); // 境界ボックス生成 D3DXVECTOR3 vMin = m_pVtx[0].pos; D3DXVECTOR3 vMax = vMin; BVERTEX* pBVtx = m_pVtx + 1; for (DWORD i = 1; i < m_dwVtx; i++, pBVtx++) { if (vMin.x > pBVtx->pos.x) vMin.x = pBVtx->pos.x; if (vMin.y > pBVtx->pos.y) vMin.y = pBVtx->pos.y; if (vMin.z > pBVtx->pos.z) vMin.z = pBVtx->pos.z; if (vMax.x < pBVtx->pos.x) vMax.x = pBVtx->pos.x; if (vMax.y < pBVtx->pos.y) vMax.y = pBVtx->pos.y; if (vMax.z < pBVtx->pos.z) vMax.z = pBVtx->pos.z; } m_vHalf = (vMax - vMin) / 2.0f; m_vCenter = (vMax + vMin) / 2.0f; // 境界球の生成 m_fRadius = 0.0f; float fR; for (DWORD i = 0; i < m_dwVtx; i++) { fR = D3DXVec3Length(&(m_pVtx[i].pos - m_vCenter)); if (m_fRadius < fR) m_fRadius = fR; } // 境界球イメージの生成 D3DXCreateSphere(CGraphics::GetDevice(), m_fRadius, 32, 16, &m_pSphere, NULL); // OBB生成 float fWidth = vMax.x - vMin.x; float fHeight = vMax.y - vMin.y; float fDepth = vMax.z - vMin.z; m_vOBBHalf.x = fWidth / 2.0f; m_vOBBHalf.y = fHeight / 2.0f; m_vOBBHalf.z = fDepth / 2.0f; // OBBイメージの生成 D3DXCreateBox(CGraphics::GetDevice() , fWidth , fHeight , fDepth , &m_pBox , NULL); return true; }
void LoadXFile(const std::string & filename, ID3DXMesh** meshOut, std::vector<Mtrl> & mtrls, std::vector<IDirect3DTexture9*> & texs) { ID3DXMesh* meshSys = 0; ID3DXBuffer * adjBuffer = 0; ID3DXBuffer * mtrlBuffer = 0; DWORD numMtrls = 0; //step 1. Load the x file into system memory HR(D3DXLoadMeshFromX(filename.c_str(), D3DXMESH_SYSTEMMEM, gd3dDevice, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &meshSys)); //step 2. look into MAX_FVF_DECL_SIZE D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; HR(meshSys->GetDeclaration(elems)); bool hasNormals = false; D3DVERTEXELEMENT9 term = D3DDECL_END(); for(int i = 0; i < MAX_FVF_DECL_SIZE; ++i) { //did we reach end? if(elems[i].Stream == 0xff) break; if(elems[i].Type == D3DDECLTYPE_FLOAT3 && elems[i].Usage == D3DDECLUSAGE_NORMAL && elems[i].UsageIndex == 0) { hasNormals = true; break; } } //step 3. D3DVERTEXELEMENT9 elements[64]; UINT numElements = 0; VertexPNT::Decl->GetDeclaration(elements, &numElements); ID3DXMesh * temp = 0; //HR(meshSys->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gd3dDevice, &temp)); HR(meshSys->CloneMesh(D3DXMESH_32BIT, elements, gd3dDevice, &temp)); ReleaseCOM(meshSys); meshSys = temp; //step 4 if( hasNormals == false ) HR(D3DXComputeNormals(meshSys, 0)); //step 5 HR(meshSys->Optimize(D3DXMESH_MANAGED | D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0, meshOut)); ReleaseCOM(meshSys); //Done w/ system mesh ReleaseCOM(adjBuffer); //done with buffer //step 6: get the materials and load the textures if(mtrlBuffer != 0 && numMtrls != 0) { D3DXMATERIAL *d3dxMtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(DWORD i = 0; i < numMtrls; ++i) { //save the ith material. MatD3D ambient //doesnt have a default value, so I'm setting //it to be the same as the diffuse Mtrl m; m.ambient = d3dxMtrls[i].MatD3D.Diffuse; m.diffuse = d3dxMtrls[i].MatD3D.Diffuse; m.spec = d3dxMtrls[i].MatD3D.Specular; m.specPower = d3dxMtrls[i].MatD3D.Power; mtrls.push_back(m); //check if the ith material has an associative texture if(d3dxMtrls[i].pTextureFilename != 0) { //yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; char *texFN = d3dxMtrls[i].pTextureFilename; HR(D3DXCreateTextureFromFile(gd3dDevice, texFN, &tex)); //save the loaded texure texs.push_back(tex); } else { //no texture texs.push_back( 0 ); } } } ReleaseCOM(mtrlBuffer); // done with the buffer }
bool XMeshData::Init(const std::wstring& FilePath) { Node::Init(); // 재질을 임시로 보관할 버퍼선언 LPD3DXBUFFER pD3DXMtrlBuffer; mEffect = ResourceManager::GetInstance()->LoadHLSL(L"Shader\\SkinnedMesh.fx"); if (!mEffect) { MessageBox(NULL, L"Could not HLSL file", L"ERROR", MB_OK); assert(false); return false; } if (FAILED(D3DXLoadMeshFromX(FilePath.c_str(), D3DXMESH_SYSTEMMEM, GetDevice(), NULL, &pD3DXMtrlBuffer, NULL, &mNumMaterial, &mXMesh))) { MessageBox(NULL, L"Could not find mesh file", L"ERROR", MB_OK); return false; } // 재질정보와 텍스쳐 정보를 따로 뽑아낸다. D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); mMaterial = new D3DMATERIAL9[mNumMaterial]; // 재질개수만큼 재질구조체 배열 생성 mTexture = new LPDIRECT3DTEXTURE9[mNumMaterial]; // 재질개수만큼 텍스쳐 배열 생성 for (DWORD j = 0; j<mNumMaterial; j++) { // 재질정보를 복사 mMaterial[j] = d3dxMaterials[j].MatD3D; // 주변광원정보를 Diffuse정보로 mMaterial[j].Ambient = mMaterial[j].Diffuse; mTexture[j] = NULL; if (d3dxMaterials[j].pTextureFilename != NULL && strlen(d3dxMaterials[j].pTextureFilename) > 0) { // 텍스쳐를 파일에서 로드한다 // w로 통일할껀지 정해야함 std::string FileName = "Model\\"; FileName += d3dxMaterials[j].pTextureFilename; if (FAILED(D3DXCreateTextureFromFileA(GetDevice(), FileName.c_str(), &mTexture[j]))) { MessageBox(NULL, L"Could not find texture map", L"ERROR", MB_OK); assert(false); return false; } } } SAFE_RELEASE( pD3DXMtrlBuffer ); //메쉬에 법선백터를 추가하는 부분 if (!(mXMesh->GetFVF() & D3DFVF_NORMAL)) { //가지고 있지 않다면 메쉬를 복제하고 D3DFVF_NORMAL을 추가한다. ID3DXMesh* pTempMesh = 0; mXMesh->CloneMeshFVF(D3DXMESH_MANAGED, mXMesh->GetFVF() | D3DFVF_NORMAL, //이곳에 추가 GetDevice(), &pTempMesh); // 법선을 계산한다. D3DXComputeNormals(pTempMesh, 0); mXMesh->Release(); // 기존메쉬를 제거한다 mXMesh = pTempMesh; // 기존메쉬를 법선이 계산된 메쉬로 지정한다. } // Init Vertices and Indices int VerticesNum = mXMesh->GetNumVertices(); BYTE* vertexBuffer; DWORD numBytesPerVertex = mXMesh->GetNumBytesPerVertex(); unsigned int offset = D3DXGetFVFVertexSize(mXMesh->GetFVF()); mXMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&vertexBuffer); for (WORD i = 0; i < VerticesNum; i++) mVertices.push_back(*((D3DXVECTOR3*)(vertexBuffer + i * offset))); mXMesh->UnlockVertexBuffer(); void *pIB; int IndicesNum = mXMesh->GetNumFaces(); WORD *indexBuffer = new WORD[IndicesNum * 3]; mXMesh->LockIndexBuffer(D3DLOCK_READONLY, (void**)&pIB); memcpy(indexBuffer, pIB, sizeof(WORD)*IndicesNum * 3); for (int i = 0; i < IndicesNum; ++i) mIndices.push_back(D3DXVECTOR3(indexBuffer[i * 3], indexBuffer[i * 3 + 1], indexBuffer[i * 3 + 2])); mXMesh->UnlockIndexBuffer(); delete[]indexBuffer; return true; }
HRESULT InitGeometry() { LPD3DXBUFFER pD3DXMtrlBuffer; if ( FAILED( D3DXLoadMeshFromX( L"./Resource/girl.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { MessageBox( NULL, L"Could not find girl.x", L"D3D Tutorial", MB_OK ); return E_FAIL; } D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; if ( g_pMeshMaterials == NULL ) { return E_OUTOFMEMORY; } g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; if ( g_pMeshTextures == NULL ) { return E_OUTOFMEMORY; } if ( !( g_pMesh->GetFVF() & D3DFVF_NORMAL ) ) { //가지고 있지 않다면 메쉬를 복제하고 D3DFVF_NORMAL을 추가한다. ID3DXMesh* pTempMesh = 0; g_pMesh->CloneMeshFVF( D3DXMESH_MANAGED, g_pMesh->GetFVF() | D3DFVF_NORMAL, g_pd3dDevice, &pTempMesh ); // 법선을 계산한다. D3DXComputeNormals( pTempMesh, 0 ); g_pMesh->Release(); // 기존메쉬를 제거한다 g_pMesh = pTempMesh; // 기존메쉬를 법선이 계산된 메쉬로 지정한다. } for ( DWORD i = 0; i < g_dwNumMaterials; ++i ) { g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D; g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse; g_pMeshTextures[i] = NULL; if ( d3dxMaterials[i].pTextureFilename != NULL && lstrlenA( d3dxMaterials[i].pTextureFilename ) > 0 ) { if ( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, d3dxMaterials[i].pTextureFilename, &g_pMeshTextures[i] ) ) ) { const CHAR* strPrefix = "./Resource/"; CHAR strTexture[MAX_PATH]; strcpy_s( strTexture, MAX_PATH, strPrefix ); strcat_s( strTexture, MAX_PATH, d3dxMaterials[i].pTextureFilename ); if ( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, strTexture, &g_pMeshTextures[i] ) ) ) { MessageBox( NULL, L"Could not find texture map", L"D3D Tutorial", MB_OK ); } } } } pD3DXMtrlBuffer->Release(); return S_OK; }
//----------------------------------------------------------------------------- // Convert the mesh to the format specified by the given vertex declarations. //----------------------------------------------------------------------------- HRESULT CDXUTMesh::SetVertexDecl( LPDIRECT3DDEVICE9 pd3dDevice, const D3DVERTEXELEMENT9 *pDecl, bool bAutoComputeNormals, bool bAutoComputeTangents, bool bSplitVertexForOptimalTangents ) { LPD3DXMESH pTempMesh = NULL; if( m_pMesh ) { if( FAILED( m_pMesh->CloneMesh( m_pMesh->GetOptions(), pDecl, pd3dDevice, &pTempMesh ) ) ) { SAFE_RELEASE( pTempMesh ); return E_FAIL; } } // Check if the old declaration contains a normal. bool bHadNormal = false; bool bHadTangent = false; D3DVERTEXELEMENT9 aOldDecl[MAX_FVF_DECL_SIZE]; if( m_pMesh && SUCCEEDED( m_pMesh->GetDeclaration( aOldDecl ) ) ) { for( UINT index = 0; index < D3DXGetDeclLength( aOldDecl ); ++index ) { if( aOldDecl[index].Usage == D3DDECLUSAGE_NORMAL ) { bHadNormal = true; } if( aOldDecl[index].Usage == D3DDECLUSAGE_TANGENT ) { bHadTangent = true; } } } // Check if the new declaration contains a normal. bool bHaveNormalNow = false; bool bHaveTangentNow = false; D3DVERTEXELEMENT9 aNewDecl[MAX_FVF_DECL_SIZE]; if( pTempMesh && SUCCEEDED( pTempMesh->GetDeclaration( aNewDecl ) ) ) { for( UINT index = 0; index < D3DXGetDeclLength( aNewDecl ); ++index ) { if( aNewDecl[index].Usage == D3DDECLUSAGE_NORMAL ) { bHaveNormalNow = true; } if( aNewDecl[index].Usage == D3DDECLUSAGE_TANGENT ) { bHaveTangentNow = true; } } } SAFE_RELEASE( m_pMesh ); if( pTempMesh ) { m_pMesh = pTempMesh; if( !bHadNormal && bHaveNormalNow && bAutoComputeNormals ) { // Compute normals in case the meshes have them D3DXComputeNormals( m_pMesh, NULL ); } if( bHaveNormalNow && !bHadTangent && bHaveTangentNow && bAutoComputeTangents ) { ID3DXMesh* pNewMesh; HRESULT hr; DWORD *rgdwAdjacency = NULL; rgdwAdjacency = new DWORD[m_pMesh->GetNumFaces() * 3]; if( rgdwAdjacency == NULL ) return E_OUTOFMEMORY; V( m_pMesh->GenerateAdjacency(1e-6f,rgdwAdjacency) ); float fPartialEdgeThreshold; float fSingularPointThreshold; float fNormalEdgeThreshold; if( bSplitVertexForOptimalTangents ) { fPartialEdgeThreshold = 0.01f; fSingularPointThreshold = 0.25f; fNormalEdgeThreshold = 0.01f; } else { fPartialEdgeThreshold = -1.01f; fSingularPointThreshold = 0.01f; fNormalEdgeThreshold = -1.01f; } // Compute tangents, which are required for normal mapping hr = D3DXComputeTangentFrameEx( m_pMesh, D3DDECLUSAGE_TEXCOORD, 0, D3DDECLUSAGE_TANGENT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0, 0, rgdwAdjacency, fPartialEdgeThreshold, fSingularPointThreshold, fNormalEdgeThreshold, &pNewMesh, NULL ); SAFE_DELETE_ARRAY( rgdwAdjacency ); if( FAILED(hr) ) return hr; SAFE_RELEASE( m_pMesh ); m_pMesh = pNewMesh; } } return S_OK; }
void LoadXFile( const std::string& filename, ID3DXMesh** meshOut, std::vector<Mtrl>& mtrls, std::vector<IDirect3DTexture9*>& texs) { // Step 1: Load the .x file from file into a system memory mesh. ID3DXMesh* meshSys = 0; ID3DXBuffer* adjBuffer = 0; ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; HR(D3DXLoadMeshFromX(filename.c_str(), D3DXMESH_SYSTEMMEM, gd3dDevice, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &meshSys)); // Step 2: Find out if the mesh already has normal info? D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; HR(meshSys->GetDeclaration(elems)); bool hasNormals = false; D3DVERTEXELEMENT9 term = D3DDECL_END(); for(int i = 0; i < MAX_FVF_DECL_SIZE; ++i) { // Did we reach D3DDECL_END() {0xFF,0,D3DDECLTYPE_UNUSED, 0,0,0}? if(elems[i].Stream == 0xff ) break; if( elems[i].Type == D3DDECLTYPE_FLOAT3 && elems[i].Usage == D3DDECLUSAGE_NORMAL && elems[i].UsageIndex == 0 ) { hasNormals = true; break; } } // Step 3: Change vertex format to VertexPNT. D3DVERTEXELEMENT9 elements[64]; UINT numElements = 0; VertexPNT::Decl->GetDeclaration(elements, &numElements); ID3DXMesh* temp = 0; HR(meshSys->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gd3dDevice, &temp)); ReleaseCOM(meshSys); meshSys = temp; // Step 4: If the mesh did not have normals, generate them. if( hasNormals == false) HR(D3DXComputeNormals(meshSys, 0)); // Step 5: Optimize the mesh. HR(meshSys->Optimize(D3DXMESH_MANAGED | D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0, meshOut)); ReleaseCOM(meshSys); // Done w/ system mesh. ReleaseCOM(adjBuffer); // Done with buffer. // Step 6: Extract the materials and load the textures. if( mtrlBuffer != 0 && numMtrls != 0 ) { D3DXMATERIAL* d3dxmtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(DWORD i = 0; i < numMtrls; ++i) { // Save the ith material. Note that the MatD3D property does not have an ambient // value set when its loaded, so just set it to the diffuse value. Mtrl m; m.ambient = d3dxmtrls[i].MatD3D.Diffuse; m.diffuse = d3dxmtrls[i].MatD3D.Diffuse; m.spec = d3dxmtrls[i].MatD3D.Specular; m.specPower = d3dxmtrls[i].MatD3D.Power; mtrls.push_back( m ); // Check if the ith material has an associative texture if( d3dxmtrls[i].pTextureFilename != 0 ) { // Yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; char* texFN = d3dxmtrls[i].pTextureFilename; HR(D3DXCreateTextureFromFile(gd3dDevice, texFN, &tex)); // Save the loaded texture texs.push_back( tex ); } else { // No texture for the ith subset texs.push_back( 0 ); } } } ReleaseCOM(mtrlBuffer); // done w/ buffer }