bool XFileUtils::LoadMesh( ID3DXFileData* pFileData, IDirect3DDevice9* pDevice, ID3DXMesh** pNewMesh, ID3DXBuffer** pMaterial, DWORD* pNumAttribute, GSkinInfo** pNewSkininfo) { //检查类型 _XCheckType(pFileData, "Mesh", false); DWORD nVertices = 0; DWORD nFaces = 0; _XCheckExcute(ParseBasemesh(pFileData, &nVertices, &nFaces, nullptr, nullptr, sizeof(XVertex_p3_n3_t1))); ID3DXMesh* pMesh = nullptr; if (FAILED(D3DXCreateMeshFVF(nFaces, nVertices, D3DXMESH_32BIT | D3DXMESH_MANAGED, XVertex_p3_n3_t1::fvf, pDevice, &pMesh))) return false; void* pVertices = nullptr; DWORD* pIndices = nullptr; DWORD* pAttribtues = nullptr; pMesh->LockVertexBuffer(0, &pVertices); pMesh->LockIndexBuffer(0, (void**)&pIndices); pMesh->LockAttributeBuffer(0, &pAttribtues); _XCheckExcute(ParseBasemesh(pFileData, &nVertices, &nFaces, pVertices, pIndices, sizeof(XVertex_p3_n3_t1))); _XCheckExcute(ParseNormals(pFileData, nVertices, pVertices, pIndices, sizeof(XVertex_p3_n3_t1), sizeof(D3DXVECTOR3))); _XCheckExcute(ParseTexcoord(pFileData, pVertices, sizeof(XVertex_p3_n3_t1), sizeof(D3DXVECTOR3) * 2)); _XCheckExcute(ParseMaterial(pFileData, pAttribtues, nFaces, pNumAttribute, pMaterial)); pMesh->UnlockAttributeBuffer(); pMesh->UnlockIndexBuffer(); pMesh->UnlockVertexBuffer(); *pNewMesh = pMesh; ParseSkinInfo(pFileData, pNewSkininfo); return true; }
/** Merges a set of D3DXMeshes. */ static void MergeD3DXMeshes( IDirect3DDevice9* Device, TRefCountPtr<ID3DXMesh>& OutMesh,TArray<int32>& OutBaseFaceIndex,const TArray<ID3DXMesh*>& Meshes) { TArray<D3DVERTEXELEMENT9> VertexElements; GetD3D9MeshVertexDeclarations(VertexElements); // Count the number of faces and vertices in the input meshes. int32 NumFaces = 0; int32 NumVertices = 0; for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++) { NumFaces += Meshes[MeshIndex]->GetNumFaces(); NumVertices += Meshes[MeshIndex]->GetNumVertices(); } // Create mesh for source data VERIFYD3D9RESULT(D3DXCreateMesh( NumFaces, NumVertices, D3DXMESH_SYSTEMMEM, (D3DVERTEXELEMENT9*)VertexElements.GetData(), Device, OutMesh.GetInitReference() ) ); // Fill D3DXMesh FUtilVertex* ResultVertices; uint16* ResultIndices; ::DWORD * ResultAttributes; OutMesh->LockVertexBuffer(0,(LPVOID*)&ResultVertices); OutMesh->LockIndexBuffer(0,(LPVOID*)&ResultIndices); OutMesh->LockAttributeBuffer(0, &ResultAttributes); int32 BaseVertexIndex = 0; int32 BaseFaceIndex = 0; for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++) { ID3DXMesh* Mesh = Meshes[MeshIndex]; FUtilVertex* Vertices; uint16* Indices; ::DWORD * Attributes; Mesh->LockVertexBuffer(0,(LPVOID*)&Vertices); Mesh->LockIndexBuffer(0,(LPVOID*)&Indices); Mesh->LockAttributeBuffer(0, &Attributes); for(uint32 FaceIndex = 0;FaceIndex < Mesh->GetNumFaces();FaceIndex++) { for(uint32 VertexIndex = 0;VertexIndex < 3;VertexIndex++) { *ResultIndices++ = BaseVertexIndex + *Indices++; } } OutBaseFaceIndex.Add(BaseFaceIndex); BaseFaceIndex += Mesh->GetNumFaces(); FMemory::Memcpy(ResultVertices,Vertices,Mesh->GetNumVertices() * sizeof(FUtilVertex)); ResultVertices += Mesh->GetNumVertices(); BaseVertexIndex += Mesh->GetNumVertices(); FMemory::Memcpy(ResultAttributes,Attributes,Mesh->GetNumFaces() * sizeof(uint32)); ResultAttributes += Mesh->GetNumFaces(); Mesh->UnlockIndexBuffer(); Mesh->UnlockVertexBuffer(); Mesh->UnlockAttributeBuffer(); } OutMesh->UnlockIndexBuffer(); OutMesh->UnlockVertexBuffer(); OutMesh->UnlockAttributeBuffer(); }
void Terrain::buildSubGridMesh(RECT& R, VertexPNT* gridVerts) { //=============================================================== // Create the subgrid mesh. ID3DXMesh* subMesh = 0; D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; UINT numElems = 0; HR(VertexPNT::Decl->GetDeclaration(elems, &numElems)); HR(D3DXCreateMesh(SubGrid::NUM_TRIS, SubGrid::NUM_VERTS, D3DXMESH_MANAGED, elems, gd3dDevice, &subMesh)); //=============================================================== // Build Vertex Buffer. Copy rectangle of vertices from the // grid into the subgrid structure. VertexPNT* v = 0; HR(subMesh->LockVertexBuffer(0, (void**)&v)); int k = 0; for(int i = R.top; i <= R.bottom; ++i) { for(int j = R.left; j <= R.right; ++j) { v[k++] = gridVerts[i*mVertCols+j]; } } //=============================================================== // Compute the bounding box before unlocking the vertex buffer. AABB bndBox; HR(D3DXComputeBoundingBox((D3DXVECTOR3*)v, subMesh->GetNumVertices(), sizeof(VertexPNT), &bndBox.minPt, &bndBox.maxPt)); HR(subMesh->UnlockVertexBuffer()); //=============================================================== // Build Index and Attribute Buffer. // Get indices for subgrid (we don't use the verts here--the verts // are given by the parameter gridVerts). std::vector<D3DXVECTOR3> tempVerts; std::vector<DWORD> tempIndices; GenTriGrid(SubGrid::NUM_ROWS, SubGrid::NUM_COLS, mDX, mDZ, D3DXVECTOR3(0.0f, 0.0f, 0.0f), tempVerts, tempIndices); WORD* indices = 0; DWORD* attBuff = 0; HR(subMesh->LockIndexBuffer(0, (void**)&indices)); HR(subMesh->LockAttributeBuffer(0, &attBuff)); for(int i = 0; i < SubGrid::NUM_TRIS; ++i) { indices[i*3+0] = (WORD)tempIndices[i*3+0]; indices[i*3+1] = (WORD)tempIndices[i*3+1]; indices[i*3+2] = (WORD)tempIndices[i*3+2]; attBuff[i] = 0; // All in subset 0. } HR(subMesh->UnlockIndexBuffer()); HR(subMesh->UnlockAttributeBuffer()); //=============================================================== // Optimize for the vertex cache and build attribute table. DWORD* adj = new DWORD[subMesh->GetNumFaces()*3]; HR(subMesh->GenerateAdjacency(EPSILON, adj)); HR(subMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE|D3DXMESHOPT_ATTRSORT, adj, 0, 0, 0)); delete[] adj; //=============================================================== // Save the mesh and bounding box. mSubGridMeshes.push_back(subMesh); mSubGridBndBoxes.push_back(bndBox); }
ID3DXMesh* CMesh::createD3DXMesh() const { HRESULT hr; ID3DXMesh* dxMesh = 0; DWORD meshOpts = D3DXMESH_MANAGED; if( getIndexStride() == 4 ) meshOpts |= D3DXMESH_32BIT; // get declaration D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; UINT numElements; getVertexDecl().getObject()->GetDeclaration( decl, &numElements ); // create mesh hr = D3DXCreateMesh( getIndexCount()/3, getVertexCount(), meshOpts, decl, &CD3DDevice::getInstance().getDevice(), &dxMesh ); if( FAILED(hr) ) return NULL; // copy VB { const void* srcVB = lockVBRead(); void* dxVB = 0; hr = dxMesh->LockVertexBuffer( 0, &dxVB ); if( FAILED(hr) ) { dxMesh->Release(); return NULL; } memcpy( dxVB, srcVB, getVertexCount() * getVertexStride() ); hr = dxMesh->UnlockVertexBuffer(); unlockVBRead(); } // copy IB { const void* srcIB = lockIBRead(); void* dxIB = 0; hr = dxMesh->LockIndexBuffer( 0, &dxIB ); if( FAILED(hr) ) { dxMesh->Release(); return NULL; } memcpy( dxIB, srcIB, getIndexCount() * getIndexStride() ); hr = dxMesh->UnlockIndexBuffer(); unlockIBRead(); } // copy groups { int ngroups = getGroupCount(); D3DXATTRIBUTERANGE* attrs = new D3DXATTRIBUTERANGE[ngroups]; DWORD* attrBuf = 0; hr = dxMesh->LockAttributeBuffer( 0, &attrBuf ); if( FAILED(hr) ) { dxMesh->Release(); return NULL; } for( int g = 0; g < ngroups; ++g ) { attrs[g].AttribId = g; const CMesh::CGroup& group = getGroup(g); attrs[g].VertexStart = group.getFirstVertex(); attrs[g].VertexCount = group.getVertexCount(); attrs[g].FaceStart = group.getFirstPrim(); attrs[g].FaceCount = group.getPrimCount(); for( int f = 0; f < group.getPrimCount(); ++f ) *attrBuf++ = g; } dxMesh->UnlockAttributeBuffer(); hr = dxMesh->SetAttributeTable( attrs, ngroups ); delete[] attrs; } return dxMesh; }
//-------------------------------------------------------------------------------------- HRESULT CMeshLoader::Create( IDirect3DDevice9* pd3dDevice, const WCHAR* strFilename ) { HRESULT hr; WCHAR str[ MAX_PATH ] = {0}; // Start clean Destroy(); // Store the device pointer m_pd3dDevice = pd3dDevice; // Load the vertex buffer, index buffer, and subset information from a file. In this case, // an .obj file was chosen for simplicity, but it's meant to illustrate that ID3DXMesh objects // can be filled from any mesh file format once the necessary data is extracted from file. //V_RETURN( LoadGeometryFromOBJ( strFilename ) ); V_RETURN( LoadGeometryFromOBJ_Fast( strFilename ) ); // Set the current directory based on where the mesh was found WCHAR wstrOldDir[MAX_PATH] = {0}; GetCurrentDirectory( MAX_PATH, wstrOldDir ); SetCurrentDirectory( m_strMediaDir ); // Load material textures for( int iMaterial = 0; iMaterial < m_Materials.GetSize(); iMaterial++ ) { Material* pMaterial = m_Materials.GetAt( iMaterial ); if( pMaterial->strTexture[0] ) { // Avoid loading the same texture twice 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; } } // Not found, load the texture if( !bFound ) { V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, pMaterial->strTexture ) ); V_RETURN( D3DXCreateTextureFromFile( pd3dDevice, pMaterial->strTexture, &( pMaterial->pTexture ) ) ); int a = 0; } } } // Restore the original current directory SetCurrentDirectory( wstrOldDir ); // Create the encapsulated mesh ID3DXMesh* pMesh = NULL; V_RETURN( D3DXCreateMesh( m_Indices.GetSize() / 3, m_Vertices.GetSize(), D3DXMESH_MANAGED | D3DXMESH_32BIT, VERTEX_DECL, pd3dDevice, &pMesh ) ); // Copy the vertex data VERTEX* pVertex; V_RETURN( pMesh->LockVertexBuffer( 0, ( void** )&pVertex ) ); memcpy( pVertex, m_Vertices.GetData(), m_Vertices.GetSize() * sizeof( VERTEX ) ); pMesh->UnlockVertexBuffer(); m_Vertices.RemoveAll(); // Copy the index data DWORD* pIndex; V_RETURN( pMesh->LockIndexBuffer( 0, ( void** )&pIndex ) ); memcpy( pIndex, m_Indices.GetData(), m_Indices.GetSize() * sizeof( DWORD ) ); pMesh->UnlockIndexBuffer(); m_Indices.RemoveAll(); // Copy the attribute data DWORD* pSubset; V_RETURN( pMesh->LockAttributeBuffer( 0, &pSubset ) ); memcpy( pSubset, m_Attributes.GetData(), m_Attributes.GetSize() * sizeof( DWORD ) ); pMesh->UnlockAttributeBuffer(); m_Attributes.RemoveAll(); // Reorder the vertices according to subset and optimize the mesh for this graphics // card's vertex cache. 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. 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; }
void PropsDemo::buildGrass() { D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; UINT numElems = 0; HR(GrassVertex::Decl->GetDeclaration(elems, &numElems)); HR(D3DXCreateMesh(NUM_GRASS_BLOCKS*2, NUM_GRASS_BLOCKS*4, D3DXMESH_MANAGED, elems, gd3dDevice, &mGrassMesh)); GrassVertex* v = 0; WORD* k = 0; HR(mGrassMesh->LockVertexBuffer(0, (void**)&v)); HR(mGrassMesh->LockIndexBuffer(0, (void**)&k)); int indexOffset = 0; // Scale down the region in which we generate grass. int w = (int)(mTerrain->getWidth() * 0.15f); int d = (int)(mTerrain->getDepth() * 0.15f); // Randomly generate a grass block (three intersecting quads) around the // terrain in the height range [35, 50] (similar to the trees). for(int i = 0; i < NUM_GRASS_BLOCKS; ++i) { //============================================ // Construct vertices. // Generate random position in region. Note that we also shift // this region to place it in the world. float x = (float)((rand() % w) - (w*0.5f)) - 30.0f; float z = (float)((rand() % d) - (d*0.5f)) - 20.0f; float y = mTerrain->getHeight(x, z); // Only generate grass blocks in this height range. If the height // is outside this range, generate a new random position and // try again. if(y < 37.0f || y > 40.0f) { --i; // We are trying again, so decrement back the index. continue; } float sx = GetRandomFloat(0.75f, 1.25f); float sy = GetRandomFloat(0.75f, 1.25f); float sz = GetRandomFloat(0.75f, 1.25f); D3DXVECTOR3 pos(x, y, z); D3DXVECTOR3 scale(sx, sy, sz); buildGrassFin(v, k, indexOffset, pos, scale); v += 4; k += 6; } HR(mGrassMesh->UnlockVertexBuffer()); HR(mGrassMesh->UnlockIndexBuffer()); // Fill in the attribute buffer (everything in subset 0) DWORD* attributeBufferPtr = 0; HR(mGrassMesh->LockAttributeBuffer(0, &attributeBufferPtr)); for(UINT i = 0; i < mGrassMesh->GetNumFaces(); ++i) attributeBufferPtr[i] = 0; HR(mGrassMesh->UnlockAttributeBuffer()); DWORD* adj = new DWORD[mGrassMesh->GetNumFaces()*3]; HR(mGrassMesh->GenerateAdjacency(EPSILON, adj)); HR(mGrassMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_VERTEXCACHE, adj, 0, 0, 0)); delete [] adj; }