/** * \brief Called to render a mesh * \param device - the Direct3D device object * \param meshContainerBase - the mesh container * \param frameBase - frame containing the mesh * \author Keith Ditchburn \date 18 July 2005 */ void CXFileEntity::DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase) { DWORD attrSize = 0; // Cast to our extended frame type D3DXFRAME_EXTENDED *frame = (D3DXFRAME_EXTENDED*)frameBase; // Cast to our extended mesh container D3DXMESHCONTAINER_EXTENDED *meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase; // Set the world transform m_d3dDevice->SetTransform(D3DTS_WORLD, &frame->exCombinedTransformationMatrix); unsigned int pass; if (effect) { effect->SetMatrix("worldmat",&frame->exCombinedTransformationMatrix); effect->Begin(&pass,0); effect->BeginPass(0); } // Loop through all the materials in the mesh rendering each subset for (unsigned int iMaterial = 0; iMaterial < meshContainer->NumMaterials; iMaterial++) { // use the material in our extended data rather than the one in meshContainer->pMaterials[iMaterial].MatD3D //m_d3dDevice->SetMaterial( &meshContainer->exMaterials[iMaterial] ); //m_d3dDevice->SetTexture( 0, meshContainer->exTextures[iMaterial] ); // Select the mesh to draw, if there is skin then use the skinned mesh else the normal one LPD3DXMESH pDrawMesh = (meshContainer->pSkinInfo) ? meshContainer->exSkinMesh: meshContainer->MeshData.pMesh; // Finally Call the mesh draw function //pDrawMesh->DrawSubset(iMaterial); pDrawMesh->GetVertexBuffer(&vb.vb); pDrawMesh->GetIndexBuffer(&ib.ib); //D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE]; //pDrawMesh->GetDeclaration(pDecl); //renderSystem->CreateVertexDeclaration(&pDecl[0],&vb.declaration); // Получение данных о количестве вершин, индексов и полигонов dwNumVerticies = pDrawMesh->GetNumVertices(); dwNumIndecies = pDrawMesh->GetNumFaces()*3; dwNumFaces = pDrawMesh->GetNumFaces(); vb.vertexSize = (short)pDrawMesh->GetNumBytesPerVertex(); renderSystem->DrawIndexedPrimitive(vb,0,dwNumVerticies,ib,0,dwNumFaces); } if (effect) { effect->EndPass(); effect->End(); } }
void cMyASELoader::LoadMesh(){ #ifdef _DEBUG _ASSERT(m_bLoaded && "Data Not Loaded"); #endif int check = 0; for (size_t i = 0; i < m_vecASENode.size(); i++){ if (m_vecASENode[i].nRef != INT_MAX){ m_vecsubSet.push_back(m_vecASENode[i].nRef); LPD3DXMESH pMesh = NULL; HRESULT hr = D3DXCreateMeshFVF(m_vecASENode[i].vecVertex.size() / 3, m_vecASENode[i].vecVertex.size(), D3DXMESH_MANAGED, ST_PNT_VERTEX::FVF, g_pD3DDevice, &pMesh); ST_PNT_VERTEX* pV = NULL; pMesh->LockVertexBuffer(0, (LPVOID*)&pV); memcpy(pV, &m_vecASENode[i].vecVertex[0], m_vecASENode[i].vecVertex.size() * sizeof(ST_PNT_VERTEX)); pMesh->UnlockVertexBuffer(); WORD* pI = NULL; pMesh->LockIndexBuffer(0, (LPVOID*)&pI); for (size_t j = 0; j < pMesh->GetNumVertices(); ++j) { pI[j] = j; } pMesh->UnlockIndexBuffer(); DWORD* pA = NULL; pMesh->LockAttributeBuffer(0, &pA); for (size_t j = 0; j < pMesh->GetNumFaces(); j++){ pA[j] = m_vecASENode[i].nRef; } pMesh->UnlockAttributeBuffer(); std::vector<DWORD> vecAdjBuffer(m_vecASENode[i].vecVertex.size()); pMesh->GenerateAdjacency(0.0f, &vecAdjBuffer[0]); pMesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, &vecAdjBuffer[0], 0, 0, 0); m_vecMeshs.push_back(pMesh); } } m_bMeshed = true; }
/* ================================================================================ */ bool init_ff (const sD3D9_XMSH* xmesh, DWORD idx, const map_acs<crh3d9_texr>* texpool) { int32u* ptr; crh3d9_texr* texr; D3DXMATERIAL* mtrl; mtrl = (D3DXMATERIAL*)xmesh->xattr->GetBufferPointer(); mtrl += idx; if (mtrl->pTextureFilename != NULL) { texr = texpool->get(mtrl->pTextureFilename); if (texr == NULL) return (false); m_map_kd = texr->get_texr(); } else { m_map_kd = NULL; } m_idx = idx; m_msh = xmesh->xmesh; if (idx == 0) { m_nv = m_msh->GetNumVertices(); m_nt = m_msh->GetNumFaces(); } else { m_nv = m_nt = 0; } m_mtl = &mtrl->MatD3D; m_mtl->Ambient.r = m_mtl->Diffuse.r; m_mtl->Ambient.g = m_mtl->Diffuse.g; m_mtl->Ambient.b = m_mtl->Diffuse.b; m_mtl->Ambient.a = 0.0f; if (m_mtl->Diffuse.a < 1.0f) m_type |= ATTR_TYPE_ALPHAOP; if (m_map_kd != NULL) m_type |= ATTR_TYPE_TEXTURE; ptr = (int32u*)(&m_mtl->Specular); for (idx = 0; idx < 3; idx++) { if (*ptr != 0) { m_type |= ATTR_TYPE_SPECULAR; break; } ptr += 1; } return (true); }
HRESULT KG3DMesh::_LoadBSPFileFromMemory(IKG_Buffer *piBSPFile) { HRESULT hrResult = E_FAIL; HRESULT hrRetCode = E_FAIL; DWORD dwBSPVertexCount = 0; DWORD dwBSPFaceCount = 0; DWORD dwMeshVerticesCount = 0; DWORD dwMeshFacesCount = 0; LPD3DXMESH piMesh = m_ppMeshes[SMBT_NORMAL]; KG3DBsp *pBSP = NULL; ASSERT(piBSPFile); KGLOG_PROCESS_ERROR(piMesh); dwMeshFacesCount = piMesh->GetNumFaces(); dwMeshVerticesCount = piMesh->GetNumVertices(); pBSP = new KG3DBsp; KGLOG_PROCESS_ERROR(pBSP); hrRetCode = pBSP->LoadFromMemory(piBSPFile); KGLOG_COM_PROCESS_ERROR(hrRetCode); hrRetCode = pBSP->GetMeshInfo(&dwBSPVertexCount, &dwBSPFaceCount); KGLOG_COM_PROCESS_ERROR(hrRetCode); if ((dwBSPVertexCount != dwMeshVerticesCount) || (dwBSPFaceCount != dwMeshFacesCount)) { KGLogPrintf(KGLOG_ERR, "%s, BSP unmatch Mesh :(", m_scName.c_str()); KG_PROCESS_ERROR(FALSE); } ASSERT(!m_lpBsp); m_lpBsp = pBSP; pBSP = NULL; hrResult = S_OK; Exit0: KG_DELETE(pBSP); if(FAILED(hrResult)) { KGLogPrintf(KGLOG_ERR, "%s BSP加载失败", m_scName.c_str()); } return hrResult; }
HRESULT D3DXMeshCreateAttributeEnumer(LPD3DXMESH pMesh, D3DXMeshAttributeEnumer& enumer ) { _ASSERTE(! enumer.IsValid()); ZeroMemory(&enumer, sizeof(D3DXMeshAttributeEnumer)); //因为外部传入的enumer是可能重用的,这里绝对要重新清空一次 _ASSERTE(NULL != pMesh); KG_PROCESS_ERROR(NULL != pMesh); { HRESULT hr = pMesh->LockAttributeBuffer(0, reinterpret_cast<DWORD**>(&enumer.m_pBuffer)); KG_COM_PROCESS_ERROR(hr); _ASSERTE(1 == sizeof(BYTE) && 2 == sizeof(WORD) && 4 == sizeof(DWORD)); enumer.m_pMesh = pMesh; enumer.m_pMesh->AddRef(); enumer.m_dwNumFaceCount = pMesh->GetNumFaces(); return S_OK; } Exit0: return E_FAIL; }
HRESULT D3DXMeshCreateIndexEnumer( LPD3DXMESH pMesh, D3DXMeshIndexEnumer& enumer ) { _ASSERTE(! enumer.IsValid()); ZeroMemory(&enumer, sizeof(D3DXMeshIndexEnumer)); //因为外部传入的enumer是可能重用的,这里绝对要重新清空一次 _ASSERTE(NULL != pMesh); KG_PROCESS_ERROR(NULL != pMesh); { HRESULT hr = pMesh->LockIndexBuffer(0, reinterpret_cast<LPVOID*>(&enumer.m_pBuffer)); KG_COM_PROCESS_ERROR(hr); _ASSERTE(1 == sizeof(BYTE) && 2 == sizeof(WORD) && 4 == sizeof(DWORD)); enumer.m_pMesh = pMesh; enumer.m_pMesh->AddRef(); enumer.m_dwNumBytePerIndex = (pMesh->GetOptions() & D3DXMESH_32BIT) ? 4 : 2; enumer.m_dwNumIndexCount = pMesh->GetNumFaces() * 3; return S_OK; } Exit0: return E_FAIL; }
HRESULT D3DXMeshCreateByVerticesPos( DWORD dwFVF, D3DVECTOR* pPosArray, DWORD dwVertexCount , DWORD* pIndexArray, DWORD dwNumIndexCount , LPDIRECT3DDEVICE9 pDevice, DWORD dwOption, LPD3DXMESH* pRet ) { HRESULT hr = E_FAIL; LPD3DXMESH pMesh = NULL; KG_PROCESS_ERROR((dwFVF & D3DFVF_XYZ)); KG_PROCESS_ERROR(NULL != pPosArray && NULL != pIndexArray && NULL != pDevice && NULL != pRet); _ASSERTE(IsMeshValidToBeCreated(dwOption, dwVertexCount, dwNumIndexCount)); { DWORD dwNumFaces = dwNumIndexCount / 3; hr = D3DXCreateMeshFVF(dwNumFaces, dwVertexCount, dwOption, dwFVF, pDevice, &pMesh); KG_COM_PROCESS_ERROR(hr); #if defined(DEBUG) | defined(_DEBUG) ULONG uRefSave = KGGetRef(pMesh); #endif { BOOL bValidity = pMesh->GetNumVertices() == dwVertexCount && pMesh->GetNumFaces() == dwNumFaces; KG_PROCESS_ERROR(bValidity); } _ASSERTE(sizeof(BYTE) == 1); { D3DXMeshVertexEnumer vertexEnumer; hr = D3DXMeshCreateVertexEnumer(pMesh, vertexEnumer); KG_COM_PROCESS_ERROR(hr); _ASSERTE(vertexEnumer.IsValid() && vertexEnumer.GetVertexCount() == dwVertexCount); for (UINT i = 0; i < vertexEnumer.GetVertexCount(); ++i) { vertexEnumer.SetPos(i, pPosArray[i]); } } { D3DXMeshIndexEnumer indexEnumer; hr = D3DXMeshCreateIndexEnumer(pMesh, indexEnumer); KG_COM_PROCESS_ERROR(hr); _ASSERTE(indexEnumer.IsValid() && indexEnumer.GetIndexCount() <= dwNumIndexCount); for (UINT i = 0; i < indexEnumer.GetIndexCount(); ++i) { indexEnumer.SetIndex(i, pIndexArray[i]); } } D3DXMeshZeroMeshAttributes(pMesh); _ASSERTE(uRefSave == KGGetRef(pMesh)); } *pRet = pMesh; return S_OK; Exit0: SAFE_RELEASE(pMesh); return E_FAIL; }
void CreateGeometry(const char* sourceFile) { cout << endl << "Reading " << sourceFile << endl; wstring wideSourceFile(sourceFile, sourceFile + strlen(sourceFile)); // Load the mesh from the specified file LPD3DXBUFFER pD3DXMtrlBuffer; LPD3DXBUFFER pD3DXEffectInstances; HRESULT hr = D3DXLoadMeshFromX( wideSourceFile.c_str(), D3DXMESH_SYSTEMMEM, g_pd3dDevice, 0, &pD3DXMtrlBuffer, &pD3DXEffectInstances, &g_dwNumMaterials, &g_pMesh); if (FAILED(hr)) { MessageBox(0, (L"Could not find " + wideSourceFile).c_str(), L"X2CTM", MB_OK); exit(1); } DWORD* adjacencyIn = new DWORD[3 * g_pMesh->GetNumFaces()]; g_pMesh->GenerateAdjacency(0.0001f, adjacencyIn); DWORD* adjacencyOut = new DWORD[3 * g_pMesh->GetNumFaces()]; LPD3DXMESH newMesh = 0; //hr = g_pMesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT, adjacencyIn, adjacencyOut, 0, 0, &newMesh); //hr = g_pMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, adjacencyIn, adjacencyOut, 0, 0); if (FAILED(hr)) { MessageBox(0, L"Unable to build attribute table", L"Whatever", MB_OK); exit(1); } //g_pMesh = newMesh; if (WeldVertices) { DWORD beforeVertCount = g_pMesh->GetNumVertices(); DWORD beforeFaceCount = g_pMesh->GetNumFaces(); hr = D3DXWeldVertices(g_pMesh, D3DXWELDEPSILONS_WELDALL, 0, 0, 0, 0, 0); DWORD afterVertCount = g_pMesh->GetNumVertices(); DWORD afterFaceCount = g_pMesh->GetNumFaces(); } D3DXATTRIBUTERANGE table[256]; DWORD tableSize = sizeof(table) / sizeof(table[0]); g_pMesh->GetAttributeTable(&table[0], &tableSize); D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*) pD3DXMtrlBuffer->GetBufferPointer(); D3DXEFFECTINSTANCE* d3dxEffects = (D3DXEFFECTINSTANCE*) pD3DXEffectInstances->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; 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] = 0; if (d3dxMaterials[i].pTextureFilename && lstrlenA(d3dxMaterials[i].pTextureFilename) > 0) { D3DXCreateTextureFromFileA(g_pd3dDevice, d3dxMaterials[i].pTextureFilename, &g_pMeshTextures[i]); } } /* for (DWORD attrib = 0; attrib < tableSize; ++attrib) { // I'm not so sure about material-to-attribute correlation // if (attrib < g_dwNumMaterials) // { LPSTR pTexture = d3dxMaterials[attrib].pTextureFilename; LPSTR pSlash = strchr(pTexture, '\\'); if (pSlash) { pTexture = ++pSlash; } cout << "{Texture='" << pTexture << "',"; // } string subMeshFilename = string("X_") + string("Armature.ctm"); // string(pTexture).substr(0, strlen(pTexture) - 4) + ".ctm"; subMeshFilename[0] = attrib + 'A'; ExportRangeCTM(table[attrib], g_pMesh, subMeshFilename.c_str()); cout //<< table[attrib].AttribId << ' ' << "FaceStart=" << table[attrib].FaceStart << ',' << "FaceCount=" << table[attrib].FaceCount << ',' << "VertexStart=" << table[attrib].VertexStart << ',' << "VertexCount=" << table[attrib].VertexCount << '}' << endl; } */ pD3DXMtrlBuffer->Release(); // Convert the filename from .X to .CTM while preserving the full path. char destFile[_MAX_PATH]; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath_s(sourceFile, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT); _makepath_s(destFile, _MAX_PATH, drive, dir, fname, "ctm"); ExportCTM(g_pMesh, destFile); cout << "Exported " << destFile << endl; /* const WORD MISSING_ATTRIBUTE = 0xffff; WORD positionsOffset = MISSING_ATTRIBUTE; WORD normalsOffset = MISSING_ATTRIBUTE; WORD texCoordsOffset = MISSING_ATTRIBUTE; D3DVERTEXELEMENT9 vertexLayout[MAX_FVF_DECL_SIZE]; D3DVERTEXELEMENT9 endMarker = D3DDECL_END(); g_pMesh->GetDeclaration(vertexLayout); D3DVERTEXELEMENT9* pVertexLayout = &vertexLayout[0]; for (int attrib = 0; attrib < MAX_FVF_DECL_SIZE; ++attrib, pVertexLayout++) { if (0 == memcmp(&vertexLayout[attrib], &endMarker, sizeof(endMarker))) { break; } if (pVertexLayout->Stream != 0) { cout << "Nonzero stream: " << pVertexLayout->Stream << endl; continue; } if (pVertexLayout->Usage == D3DDECLUSAGE_POSITION && pVertexLayout->Type == D3DDECLTYPE_FLOAT3) { cout << "Contains positions " << (int) pVertexLayout->UsageIndex << endl; positionsOffset = pVertexLayout->Offset; } else if (pVertexLayout->Usage == D3DDECLUSAGE_NORMAL && pVertexLayout->Type == D3DDECLTYPE_FLOAT3) { cout << "Contains normals " << (int) pVertexLayout->UsageIndex << endl; normalsOffset = pVertexLayout->Offset; } else if (pVertexLayout->Usage == D3DDECLUSAGE_TEXCOORD && pVertexLayout->Type == D3DDECLTYPE_FLOAT2) { cout << "Contains texture coordinates " << (int) pVertexLayout->UsageIndex << endl; texCoordsOffset = pVertexLayout->Offset; } else { cout << "Mysterious attribute" << endl; } } // Check that we support the format of the data. if (positionsOffset == MISSING_ATTRIBUTE) { exit(1); } // Obtain vertex & index counts from the D3D mesh; allocate memory for the CTM mesh. DWORD dwVertexCount = g_pMesh->GetNumVertices(); DWORD dwTriangleCount = g_pMesh->GetNumFaces(); DWORD dwIndexCount = dwTriangleCount * 3; // Lock down the verts and pluck out the positions and normals. { void* pData = 0; if (S_OK != g_pMesh->LockVertexBuffer(0, &pData)) { exit(1); } if (positionsOffset != MISSING_ATTRIBUTE) { unsigned char* pSource = ((unsigned char*) pData) + positionsOffset; DWORD dwSourceStride = g_pMesh->GetNumBytesPerVertex(); DWORD dwDestStride = sizeof(CTMfloat) * 3; for (DWORD dwVertex = 0; dwVertex < dwVertexCount; ++dwVertex) { float* pFloat = (float*) pSource; *pFloat = -*pFloat; //*pFloat = -*pFloat; pSource += dwSourceStride; } } g_pMesh->UnlockVertexBuffer(); } // Lock down the indices and convert them to unsigned 32-bit integers. { void* pData = 0; g_pMesh->LockIndexBuffer(0, &pData); DWORD dwOptions = g_pMesh->GetOptions(); DWORD dwSourceStride = (dwOptions & D3DXMESH_32BIT) ? 4 : 2; unsigned char* pSource = (unsigned char*) pData; for (DWORD dwIndex = 0; dwIndex < dwIndexCount / 3; ++dwIndex) { unsigned short* inds = (unsigned short*) pSource; std::swap(inds[0], inds[1]); pSource += dwSourceStride * 3; } g_pMesh->UnlockIndexBuffer(); } D3DXSaveMeshToX(L"new.x", g_pMesh, 0, d3dxMaterials, d3dxEffects, g_dwNumMaterials, D3DXF_FILEFORMAT_BINARY | D3DXF_FILEFORMAT_COMPRESSED); cout << "Saved." << endl; */ }
//==================================================================================== // メッシュコンテナの作成(XFileの各パーツの集合)ようはスキンメッシュモデルをここで作る //==================================================================================== HRESULT CInheritanceHierarchy::CreateMeshContainer(LPCSTR Name, CONST D3DXMESHDATA* pMeshData, CONST D3DXMATERIAL* pMaterials, CONST D3DXEFFECTINSTANCE* pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppMeshContainer ) { //======================================================================== // コンテナ作成に当たって必要な変数を用意 //======================================================================== MYMESHCONTAINER *pMeshContainer = NULL; int iFacesAmount; DWORD iMaterial; LPDIRECT3DDEVICE9 pDevice = NULL; LPD3DXMESH pMesh = NULL; *ppMeshContainer = NULL; DWORD dwBoneNum=0; //======================================================================== // コンテナを動的確保して値を入れていく作業へ //======================================================================== pMesh = pMeshData->pMesh; pMeshContainer = new MYMESHCONTAINER; //メモリ不足のときは終了 if (pMeshContainer == NULL) { return E_OUTOFMEMORY; } //作成に成功したら中身を0で初期化しておく ZeroMemory(pMeshContainer, sizeof(MYMESHCONTAINER)); //メッシュコンテナとしてXFileでつけられてる名前を拾う pMeshContainer->Name=new TCHAR[lstrlen(Name) + 1]; // \0分の+1 //名前がなかったらおかしいので終了 if (!pMeshContainer->Name) { return E_FAIL; } //名前があるならそれにする strcpy(pMeshContainer->Name,Name); // デバイスゲット pMesh->GetDevice(&pDevice); // 面の数ゲット iFacesAmount = pMesh->GetNumFaces(); pMeshContainer->MeshData.pMesh = pMesh; pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; //通常メッシュの場合はこれが必要。スキンの場合、これをするとメモリリークになる。 if (pSkinInfo == NULL) { pMesh->AddRef(); } //メッシュのマテリアル設定 pMeshContainer->NumMaterials = max(1, NumMaterials); pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; pMeshContainer->pAdjacency = new DWORD[iFacesAmount * NUM_POLYGON_CREATE_TRIANGLE]; //隣接性情報またはマテリアルがなければ終了 if( pMeshContainer->pAdjacency == NULL || pMeshContainer->pMaterials == NULL ) { return E_FAIL; } //情報をメッシュコンテナに流し込む memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * iFacesAmount * NUM_POLYGON_CREATE_TRIANGLE); memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials); //======================================================================== //該当メッシュがスキン情報を持っている場合 //======================================================================== if (pSkinInfo != NULL) { pMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); dwBoneNum = pSkinInfo->GetNumBones(); pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[dwBoneNum]; for (DWORD i = 0; i < dwBoneNum; i++) { memcpy(&pMeshContainer->pBoneOffsetMatrices[i], pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i), sizeof(D3DMATRIX)); } // インデックスつきのものに変換 シェーダー使わないやつとは別なので注意 if (FAILED(pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh(pMesh, NULL, dwBoneNum, pMeshContainer->pAdjacency, NULL, NULL, NULL, &pMeshContainer->dwWeight, &pMeshContainer->dwBoneNum, &pMeshContainer->pBoneBuffer, &pMeshContainer->MeshData.pMesh))) { return E_FAIL; } // コンバート ConvertMesh(&pMeshContainer->MeshData.pMesh); D3DVERTEXELEMENT9 elements[] = { // 頂点ストリーム(パイプライン)番号, オフセット(頂点の型の先頭からのバイト数), データ型, DEFAULTでOK, 使用用途, 使用用途が同じものを複数使うときに仕分ける番号 { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 }, { 0, 24, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 }, { 0, 28, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 40, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, { 0, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() // 定義終了 絶対必要 }; pMeshContainer->pSkinInfo->SetDeclaration(elements); } //======================================================================== // モデルのマテリアル情報 //======================================================================== if (NumMaterials > 0) { memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials); for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++) { // マテリアルのディフーズ色を強制的に変更 pMeshContainer->pMaterials[iMaterial].MatD3D.Diffuse = DEFAULT_POLYGON_COLOR; if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL) { TCHAR strTexturePath[MAX_PATH]; strcpy( strTexturePath,TEX_FOLDER_PATH); strcat_s( strTexturePath, sizeof( char ) * MAX_LENGTH_FILE_PATH, pMeshContainer->pMaterials[iMaterial].pTextureFilename ); if (FAILED(D3DXCreateTextureFromFile(pDevice, strTexturePath, &pMeshContainer->ppTextures[iMaterial]))) { pMeshContainer->ppTextures[iMaterial] = NULL; pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL; } } } } else { pMeshContainer->pMaterials[0].pTextureFilename = NULL; memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9)); pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = COLOR_OF_NOT_EXIST_MATERIAL.r; pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = COLOR_OF_NOT_EXIST_MATERIAL.g; pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = COLOR_OF_NOT_EXIST_MATERIAL.b; pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse; } //ローカルに生成したメッシュコンテナーを呼び出し側にコピーする (コピーじゃないけど・・・) *ppMeshContainer = pMeshContainer; //参照カウンタを増やしたので減らす SAFE_RELEASE(pDevice); return S_OK; }
void MeshParameterization::GenerateCache( LPD3DXMESH meshOut, LPD3DXBUFFER remapped ) { paramVertex * pNewVerts = NULL; IToolBox * tool = EngineGetToolBox(); HRESULT hr; m_Cache.Clean(); //have to now be able to map a face to a texture area, or, a face to a chart. int numVertices = m_CollapsedMesh->size(); int numNewVertices = remapped->GetBufferSize() / sizeof( DWORD ); if( numNewVertices != numVertices ) { //Our cache is a remapping cache! New vertices were generated!!!! m_Cache.m_bRemapped = true; //First we remap our vertices int remapsize = remapped->GetBufferSize() / sizeof( DWORD ); DWORD * remappedData = (DWORD*) remapped->GetBufferPointer(); m_Cache.m_NumVertices = remapsize; m_Cache.ResizeRemappedData( remapsize ); m_Cache.ResizeUVData( remapsize*2 ); memcpy( m_Cache.m_RemappedData, remappedData, sizeof( DWORD )*remapsize ); vector< ParameterizationVertex > newVertBuffer; newVertBuffer.resize( remapsize ); //loop through and assign new vertices hr = meshOut->LockVertexBuffer( 0, (LPVOID*)&pNewVerts ); if( hr == D3D_OK && pNewVerts) { for( int i = 0; i < remapsize; i++ ) { int oldIndex = remappedData[ i ]; newVertBuffer[ i ] = (*m_CollapsedMesh)[ oldIndex ]; //UV for internal lightmap calcs NormalizeUV( pNewVerts[ i ].u ); NormalizeUV( pNewVerts[ i ].v ); newVertBuffer[ i ].generatedU = pNewVerts[ i ].u; newVertBuffer[ i ].generatedV = pNewVerts[ i ].v; //Duplicate uv to pass to render object as a stream m_Cache.m_UVData[ i*2 ] = pNewVerts[ i ].u; m_Cache.m_UVData[ i*2 + 1 ] = pNewVerts[ i ].v; } meshOut->UnlockVertexBuffer(); //assign new mesh m_CollapsedMesh->clear(); (*m_CollapsedMesh) = newVertBuffer; newVertBuffer.clear(); }else { tool->Log( LOGERROR, _T("Could not lock mesh param vertex buffer to remap vertices\n")); } //now do indices int numIndices = 3*meshOut->GetNumFaces(); m_Cache.m_NumIndices = numIndices; m_Cache.ResizeRemappedIndices( numIndices ); WORD * pIndices = NULL; hr = meshOut->LockIndexBuffer( 0, (LPVOID*)&pIndices ); if( hr == D3D_OK && pIndices) { for( int i = 0; i < numIndices; i++ ) { m_Cache.m_RemappedIndices[ i ] = (DWORD)pIndices[ i ]; //faces int faceIndex = i/3; int triIndex = i%3; (*m_Faces)[ faceIndex ].index[ triIndex ] = pIndices[ i ]; } }else if( tool ) { tool->Log( LOGERROR, _T("Could not lock mesh param index buffer to remap indices\n")); } } else //no remapping, just uvs needed { BYTE * pNewVerts = NULL; hr = meshOut->LockVertexBuffer( 0, (LPVOID*)&pNewVerts ); m_Cache.m_NumVertices = m_CollapsedMesh->size(); m_Cache.ResizeUVData( m_Cache.m_NumVertices*2 ); if( hr == D3D_OK ) { //copy new uvs paramVertex * pv = (paramVertex*)pNewVerts; for( int i = 0; i < (int)m_CollapsedMesh->size(); i++ ) { NormalizeUV( pv[ i ].u ); NormalizeUV( pv[ i ].v ); (*m_CollapsedMesh)[i].generatedU = pv[ i ].u; (*m_CollapsedMesh)[i].generatedV = pv[ i ].v; //copy uvs for passing to render object as a stream m_Cache.m_UVData[ i*2 ] = pv[ i ].u; m_Cache.m_UVData[ i*2 + 1 ] = pv[ i ].v; } meshOut->UnlockVertexBuffer(); } } }
int main(int argc, char* argv[]) { if (argc < 3) { puts("Usage: MeshConv meshfile rdffile"); return 1; } // Initialize DirectDraw pD3D = Direct3DCreate9(D3D_SDK_VERSION); if (pD3D == NULL) { puts("Cannot init D3D"); return 1; } MeshMender mender; std::vector<MeshMender::Vertex> MendVerts; std::vector<unsigned int> MendIndices; std::vector<unsigned int> mappingNewToOld; HRESULT hr; D3DDISPLAYMODE dispMode; D3DPRESENT_PARAMETERS presentParams; pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dispMode); ZeroMemory(&presentParams, sizeof(presentParams)); presentParams.Windowed = TRUE; presentParams.hDeviceWindow = GetConsoleWindow(); presentParams.SwapEffect = D3DSWAPEFFECT_COPY; presentParams.BackBufferWidth = 8; presentParams.BackBufferHeight = 8; presentParams.BackBufferFormat = dispMode.Format; hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParams, &pD3DDevice); if (FAILED(hr)) { printf("Cannot init D3D device: %08x\n", hr); pD3D->Release(); return 1; } printf("Loading mesh %s: ", argv[1]); LPD3DXBUFFER pAdjacency, pMaterials, pEffects; DWORD n; LPD3DXMESH pLoadMesh; hr = D3DXLoadMeshFromX(argv[1], D3DXMESH_SYSTEMMEM, pD3DDevice, &pAdjacency, &pMaterials, &pEffects, &n, &pLoadMesh); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); goto mesherror; } pEffects->Release(); pMaterials->Release(); printf("%d faces, %d verts\n", pLoadMesh->GetNumFaces(), pLoadMesh->GetNumVertices()); LPD3DXMESH pMesh; if (pLoadMesh->GetFVF() != MESHFVF) { hr = pLoadMesh->CloneMeshFVF(D3DXMESH_SYSTEMMEM, MESHFVF, pD3DDevice, &pMesh); pLoadMesh->Release(); if (FAILED(hr)) { printf("CloneMesh error: %08x\n", hr); goto mesherror; } } else pMesh = pLoadMesh; printf("Welding verts: "); DWORD* pAdj = new DWORD[pAdjacency->GetBufferSize() / 4]; D3DXWELDEPSILONS Eps; memset(&Eps, 0, sizeof(Eps)); hr = D3DXWeldVertices(pMesh, D3DXWELDEPSILONS_WELDPARTIALMATCHES, &Eps, (DWORD*)pAdjacency->GetBufferPointer(), pAdj, NULL, NULL); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); goto mesherror; } hr = pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, pAdj, (DWORD*)pAdjacency->GetBufferPointer(), NULL, NULL); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); goto mesherror; } pAdjacency->Release(); delete [] pAdj; printf("%d faces, %d verts\n", pMesh->GetNumFaces(), pMesh->GetNumVertices()); printf("Mending mesh: "); DWORD NumVerts = pMesh->GetNumVertices(); DWORD NumFaces = pMesh->GetNumFaces(); MESHVERT* MeshVert; pMesh->LockVertexBuffer(0, (LPVOID*)&MeshVert); //fill up Mend vectors with your mesh's data MendVerts.reserve(NumVerts); for(DWORD i = 0; i < NumVerts; ++i) { MeshMender::Vertex v; v.pos = MeshVert[i].pos; v.s = MeshVert[i].s; v.t = MeshVert[i].t; v.normal = MeshVert[i].norm; MendVerts.push_back(v); } pMesh->UnlockVertexBuffer(); WORD* MeshIdx; pMesh->LockIndexBuffer(0, (LPVOID*)&MeshIdx); MendIndices.reserve(NumFaces * 3); for(DWORD i = 0; i < NumFaces * 3; ++i) { MendIndices.push_back(MeshIdx[i]); } pMesh->UnlockIndexBuffer(); pMesh->Release(); pMesh = 0; //pass it in to Mend mender to do it's stuff mender.Mend(MendVerts, MendIndices, mappingNewToOld, 0.9f, 0.9f, 0.9f, 1.0f, MeshMender::DONT_CALCULATE_NORMALS, MeshMender::RESPECT_SPLITS); mappingNewToOld.clear(); printf("%d faces, %d verts\n", MendIndices.size() / 3, MendVerts.size()); printf("Saving data: "); FILE* fp = fopen("meshdata.bin", "wb"); n = MendIndices.size() / 3; fwrite(&n, 4, 1, fp); n = MendVerts.size(); fwrite(&n, 4, 1, fp); fclose(fp); // Load existing file HANDLE hFile = CreateFile(argv[2], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); if (hFile == INVALID_HANDLE_VALUE) { printf("ERROR: %08x\n", GetLastError()); goto mesherror; } DWORD Size = GetFileSize(hFile, 0); char* FileData = (char*)VirtualAlloc(0, 64*1024*1024, MEM_RESERVE, PAGE_NOACCESS); VirtualAlloc(FileData, Size, MEM_COMMIT, PAGE_READWRITE); ReadFile(hFile, FileData, Size, &n, 0); FileData[n] = 0; Size = n; char *p, *q; // Find vertex data p = strstr(FileData, "VertexBuffer"); if (!p) { printf("ERROR: Invalid output file\n"); goto mesherror; } p = strchr(p, '{'); q = p+1; int depth = 1; do { if (*q == '}') --depth; else if (*q == '{') ++depth; ++q; } while (depth > 0); // move post-vertex data to temp buffer Size = (FileData + Size) - q; char* TempData = (char*)VirtualAlloc(0, Size, MEM_COMMIT, PAGE_READWRITE); memcpy(TempData, q, Size); // write vertex data strcpy(p, "{\r\n VertexFormat {D3DVSDT_FLOAT3 D3DVSDT_NORMPACKED3 D3DVSDT_FLOAT2 D3DVSDT_NORMPACKED3 D3DVSDT_NORMPACKED3}\r\n VertexData\r\n {\r\n"); p += strlen(p); for (std::vector<MeshMender::Vertex>::iterator i = MendVerts.begin(); i != MendVerts.end(); ++i) { VirtualAlloc(p, 500, MEM_COMMIT, PAGE_READWRITE); p += sprintf(p, " %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f\r\n", i->pos.x, i->pos.y, i->pos.z, i->normal.x, i->normal.y, i->normal.z, i->s, i->t, i->tangent.x, i->tangent.y, i->tangent.z, i->binormal.x, i->binormal.y, i->binormal.z); } strcpy(p, " }\r\n}"); p += strlen(p); VirtualAlloc(p, Size, MEM_COMMIT, PAGE_READWRITE); memcpy(p, TempData, Size); Size += p - FileData; VirtualFree(TempData, 0, MEM_RELEASE); // Find index data p = strstr(FileData, "IndexBuffer"); if (!p) { printf("ERROR: Invalid output file\n"); goto mesherror; } p = strchr(p, '{'); q = p+1; depth = 1; do { if (*q == '}') --depth; else if (*q == '{') ++depth; ++q; } while (depth > 0); // move post-index data to temp buffer Size = (FileData + Size) - q; TempData = (char*)VirtualAlloc(0, Size, MEM_COMMIT, PAGE_READWRITE); memcpy(TempData, q, Size); // write index data strcpy(p, "{\r\n IndexData\r\n {\r\n "); p += strlen(p); n = 0; for (std::vector<unsigned>::iterator i = MendIndices.begin(); i != MendIndices.end(); ++i) { VirtualAlloc(p, 20, MEM_COMMIT, PAGE_READWRITE); p += sprintf(p, " %5hu", *i); if (n++ == 2) { p += sprintf(p, "\r\n "); n = 0; } } strcpy(p-3, "}\r\n}"); p += strlen(p); VirtualAlloc(p, Size, MEM_COMMIT, PAGE_READWRITE); memcpy(p, TempData, Size); Size += p - FileData; VirtualFree(TempData, 0, MEM_RELEASE); SetFilePointer(hFile, 0, 0, FILE_BEGIN); WriteFile(hFile, FileData, Size, &n, 0); SetEndOfFile(hFile); CloseHandle(hFile); VirtualFree(FileData, 0, MEM_RELEASE); printf("Done\n"); pD3D->Release(); pD3DDevice->Release(); return 0; mesherror: pD3D->Release(); pD3DDevice->Release(); return 1; }
HRESULT AllocateHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer) { HRESULT hr; D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL; UINT NumFaces; UINT iMaterial; UINT iBone, cBones; LPDIRECT3DDEVICE9 pd3dDevice = NULL; 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; goto e_Exit; } // get the pMesh interface pointer out of the mesh data structure pMesh = pMeshData->pMesh; // this sample does not FVF compatible meshes, so fail when one is found if (pMesh->GetFVF() == 0) { hr = E_FAIL; goto e_Exit; } // allocate the overloaded structure to return as a D3DXMESHCONTAINER pMeshContainer = new D3DXMESHCONTAINER_DERIVED; if (pMeshContainer == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED)); // 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)) goto e_Exit; pMesh->GetDevice(&pd3dDevice); 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, pd3dDevice, &pMeshContainer->MeshData.pMesh ); if (FAILED(hr)) goto e_Exit; // 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; goto e_Exit; } 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) { string strTexturePath; string strFilename = _pSkinmesh->GetMeshname(); strFilename = strFilename + "\\" + pMeshContainer->pMaterials[iMaterial].pTextureFilename; strTexturePath = MODEL_DIR(strFilename.c_str()); if( FAILED( Moon_CreateTexture( pd3dDevice, const_cast<char*>(strTexturePath.c_str()), &pMeshContainer->ppTextures[iMaterial] ) ) ) pMeshContainer->ppTextures[iMaterial] = NULL; // 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; goto e_Exit; } // 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)); } // GenerateSkinnedMesh will take the general skinning information and transform it to a HW friendly version hr = _pSkinmesh->GenerateSkinmesh(pMeshContainer); if (FAILED(hr)) goto e_Exit; } *ppNewMeshContainer = pMeshContainer; pMeshContainer = NULL; e_Exit: SAFE_RELEASE(pd3dDevice); // call Destroy function to properly clean up the memory allocated if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; }
//====================================================================== // <<<メッシュ コンテナ オブジェクトの割り当て要求の実装>>> // Name : [in] メッシュの名前 // pMeshData : [in] メッシュデータ構造体へのポインタ // pMaterials : [in] メッシュに使うマテリアルの配列 // pEffectInstances : [in] メッシュに使うエフェクトインスタンスの配列 // NumMaterials : [in] マテリアル配列内のマテリアルの数 // pAdjacency : [in] メッシュの隣接性配列 // pSkinInfo : [in] スキンデータが見つかった場合のスキンメッシュオブジェクトへのポインタ // ppNewMeshContainer : [out, retval] 作成されたメッシュコンテナを返す //====================================================================== HRESULT CAllocateHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer) { HRESULT hr = S_OK; *ppNewMeshContainer = NULL; // patch meshes を扱う事はできない if( pMeshData->Type != D3DXMESHTYPE_MESH ) { return E_FAIL; } LPD3DXMESH pMesh = pMeshData->pMesh; // FVF で記述されたメッシュ以外は読めぬ if( pMesh->GetFVF() == 0 ) { return E_FAIL; } UINT NumFaces = pMesh->GetNumFaces(); // メッシュ作成 CXMesh *pCXMesh = NULL; try { pCXMesh = new CXMesh; } catch ( std::bad_alloc& ) { // メモリが足りない return E_OUTOFMEMORY; } // 名前設定 pCXMesh->SetName( Name ); // メッシュタイプ設定 pCXMesh->MeshData.Type = D3DXMESHTYPE_MESH; LPDIRECT3DDEVICE9 pD3DDevice = NULL; // デバイスを取得 if( FAILED( pMesh->GetDevice( &pD3DDevice ) ) ) { hr = E_FAIL; goto e_Exit; } // Xファイルに法線が無かったら計算で求める if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) ) { ////FVFに法線を追加した新しいメッシュにする//// hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pD3DDevice, &pCXMesh->MeshData.pMesh ); if( FAILED( hr ) ) { goto e_Exit; } // 引数で渡されたメッシュへのポインタに新しいメッシュへのポインタをセット // pMeshへの参照はこの時点で存在しないので、ここではreleaseをかけない pMesh = pCXMesh->MeshData.pMesh; D3DXComputeNormals( pMesh, NULL ); } // 法線があった else { // リファレンスを増やすだけ pCXMesh->MeshData.pMesh = pMesh; pMesh->AddRef(); } // マテリアル用のメモリを確保 pCXMesh->NumMaterials = max( 1, NumMaterials ); try { pCXMesh->pMaterials = new D3DXMATERIAL[pCXMesh->NumMaterials]; pCXMesh->m_ppTextures = new LPDIRECT3DTEXTURE9[pCXMesh->NumMaterials]; pCXMesh->pAdjacency = new DWORD[NumFaces * 3]; } catch ( std::bad_alloc& ) { // メモリが足りない goto e_Exit; } memcpy( pCXMesh->pAdjacency, pAdjacency, sizeof( DWORD ) * NumFaces * 3 ); memset( pCXMesh->m_ppTextures, 0, sizeof( LPDIRECT3DTEXTURE9 ) * pCXMesh->NumMaterials ); // マテリアルのコピー if( NumMaterials > 0 ) { memcpy( pCXMesh->pMaterials, pMaterials, sizeof( D3DXMATERIAL ) * NumMaterials ); for( UINT i=0; i<NumMaterials; i++ ) { if( pCXMesh->pMaterials[i].pTextureFilename != NULL ) { // テクスチャを読み込む if( FAILED( D3DXCreateTextureFromFileEx( pD3DDevice, pCXMesh->pMaterials[i].pTextureFilename, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_RENDERTARGET, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, m_KeyColor, NULL, NULL, &pCXMesh->m_ppTextures[i] ) ) ) { // 読み込み失敗 pCXMesh->m_ppTextures[i] = NULL; } pD3DDevice->SetTexture(0, pCXMesh->m_ppTextures[i]); pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, true); pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); pD3DDevice->SetRenderState(D3DRS_ALPHAREF, 8); } } } // マテリアルが無いので適当にセット else { pCXMesh->pMaterials[0].pTextureFilename = NULL; memset( &pCXMesh->pMaterials[0].MatD3D, 0, sizeof( D3DMATERIAL9 ) ); pCXMesh->pMaterials[0].MatD3D.Diffuse.r = 0.5f; pCXMesh->pMaterials[0].MatD3D.Diffuse.g = 0.5f; pCXMesh->pMaterials[0].MatD3D.Diffuse.b = 0.5f; pCXMesh->pMaterials[0].MatD3D.Specular = pCXMesh->pMaterials[0].MatD3D.Diffuse; } // ワンスキン形式のXファイルだった時の処理 if( pSkinInfo != NULL ) { /* スキンメッシュ用の処理*/ /*pSkinInfo と pMesh をセット*/ pCXMesh->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); pCXMesh->m_pOrigMesh = pMesh; pMesh->AddRef(); /* Bone Offset Matrices 保存用のメモリを確保*/ UINT NumBones = pSkinInfo->GetNumBones(); try { pCXMesh->m_pBoneOffsetMatrices = new D3DXMATRIX[NumBones]; } catch ( std::bad_alloc& ) { // メモリが足りない goto e_Exit; } /*Bone Offset Matrices 読み込み*/ for( UINT i = 0; i < NumBones; i++ ) { //memcpy(&pCXMesh->m_pBoneOffsetMatrices[i], pCXMesh->pSkinInfo->GetBoneOffsetMatrix(i), sizeof(D3DMATRIX) ); pCXMesh->m_pBoneOffsetMatrices[i] = *(pCXMesh->pSkinInfo->GetBoneOffsetMatrix( i ) ); } // ジェネレート処理 hr = m_pModel->GenerateSkinnedMesh( m_pD3DX9, pCXMesh, m_MaxBlend ); if( FAILED( hr ) ) { goto e_Exit; } } // メッシュコンテナの割り当て。 // CXMeshクラスは D3DXMESHCONTAINER を継承している *ppNewMeshContainer = pCXMesh; pCXMesh = NULL; e_Exit: // 開放処理 F_RELEASE( pD3DDevice ); if( pCXMesh != NULL ) { DestroyMeshContainer( pCXMesh ); } return hr; }
void Sombra::ConstruirSombra(LPD3DXMESH pMesh, D3DXVECTOR3 vLight) { // Note: the MeshVertex format depends on the FVF of the mesh struct MeshVertex { D3DXVECTOR3 p, n; DWORD diffuse; float tu,tv; }; MeshVertex *pVertices; WORD *pIndices; // Lock the geometry buffers pMesh->LockVertexBuffer( 0L, (LPVOID*)&pVertices ); pMesh->LockIndexBuffer( 0L, (LPVOID*)&pIndices ); DWORD dwNumFaces = pMesh->GetNumFaces(); // Allocate a temporary edge list WORD *pEdges = new WORD[dwNumFaces*6]; if( pEdges == NULL ) { pMesh->UnlockVertexBuffer(); pMesh->UnlockIndexBuffer(); return ; } DWORD dwNumEdges = 0; // For each face for( DWORD i = 0; i < dwNumFaces; ++i ) { WORD wFace0 = pIndices[3*i+0]; WORD wFace1 = pIndices[3*i+1]; WORD wFace2 = pIndices[3*i+2]; D3DXVECTOR3 v0 = pVertices[wFace0].p; D3DXVECTOR3 v1 = pVertices[wFace1].p; D3DXVECTOR3 v2 = pVertices[wFace2].p; // Transform vertices or transform light? D3DXVECTOR3 vCross1(v2-v1); D3DXVECTOR3 vCross2(v1-v0); D3DXVECTOR3 vNormal; D3DXVec3Cross( &vNormal, &vCross1, &vCross2 ); if( D3DXVec3Dot( &vNormal, &vLight ) >= 0.0f ) { InsertarSegmento( pEdges, dwNumEdges, wFace0, wFace1 ); InsertarSegmento( pEdges, dwNumEdges, wFace1, wFace2 ); InsertarSegmento( pEdges, dwNumEdges, wFace2, wFace0 ); } } // Se construyen las caras de la sombra extrudando los segmentos en la dirección // de la luz y una longitud 10 veces la del vector luz. for( i = 0; i < dwNumEdges; ++i ) { D3DXVECTOR3 v1 = pVertices[pEdges[2*i+0]].p; D3DXVECTOR3 v2 = pVertices[pEdges[2*i+1]].p; D3DXVECTOR3 v3 = v1 - vLight/10; D3DXVECTOR3 v4 = v2 - vLight/10; // Add a quad (two triangles) to the vertex list m_pVertices[m_dwNumVertices++] = v1; m_pVertices[m_dwNumVertices++] = v2; m_pVertices[m_dwNumVertices++] = v3; m_pVertices[m_dwNumVertices++] = v2; m_pVertices[m_dwNumVertices++] = v4; m_pVertices[m_dwNumVertices++] = v3; } // Delete the temporary edge list delete[] pEdges; // Unlock the geometry buffers pMesh->UnlockVertexBuffer(); pMesh->UnlockIndexBuffer(); }
//----------------------------------------------------------------------------- // Name: InitGeometry() // Desc: Load the mesh and build the material and texture arrays //----------------------------------------------------------------------------- HRESULT InitGeometry() { LPD3DXBUFFER pD3DXMtrlBuffer; LPDIRECT3DVERTEXBUFFER9 pMeshSourceVB; LPDIRECT3DINDEXBUFFER9 pMeshSourceIB; D3DVERTEX* pSrc; D3DVERTEX* pDst; // load the textures we are going to be using if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"cartoonpallet-white-to-black.bmp", &g_pTexture ) ) ) MessageBox(NULL, L"Texture Load Problem", NULL, NULL); if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"cartoonpallet-black-to-white.bmp", &g_pTexture2 ) ) ) MessageBox(NULL, L"Texture Load Problem", NULL, NULL); if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"marble.bmp", &marbleTexture ) ) ) MessageBox(NULL, L"Texture Load Problem", NULL, NULL); if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"background.jpg", &backgroundTexture ) ) ) MessageBox(NULL, L"Texture Load Problem", NULL, NULL); // Load the mesh from the specified file if( FAILED( D3DXLoadMeshFromX( L"skull.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) g_pd3dDevice->SetFVF(D3DFVF_D3DVERTEX ); g_dwNumVertices = g_pMesh->GetNumVertices(); g_dwNumFaces = g_pMesh->GetNumFaces(); //Clone the mesh to set the FVF LPD3DXMESH pTempSysMemMesh = NULL; if( FAILED( g_pMesh->CloneMeshFVF( D3DXMESH_SYSTEMMEM, D3DFVF_D3DVERTEX, g_pd3dDevice, &pTempSysMemMesh ) ) ) MessageBox(NULL,L"Mesh clone problem",NULL,NULL); g_pMesh->Release(); g_pMesh = pTempSysMemMesh; //Compute normals in case the meshes have them if( g_pMesh ) D3DXComputeNormals( g_pMesh, NULL ); //Meshes cloned if( FAILED(g_pd3dDevice->CreateVertexBuffer( g_dwNumVertices * sizeof(D3DVERTEX), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &g_pMeshVB, NULL ))) MessageBox(NULL,L"Vertex buffer create problem",NULL,NULL); if( FAILED(g_pd3dDevice->CreateIndexBuffer( g_dwNumFaces * 3 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &g_pMeshIB, NULL ))) MessageBox(NULL,L"Index buffer create problem",NULL,NULL); g_pMesh->GetVertexBuffer(&pMeshSourceVB); g_pMeshVB->Lock( 0, 0, (void**)&pDst, 0 ); pMeshSourceVB->Lock( 0, 0, (void**)&pSrc, 0 ); memcpy( pDst, pSrc, g_dwNumVertices * sizeof(D3DVERTEX) ); g_pMeshVB->Unlock(); pMeshSourceVB->Unlock(); pMeshSourceVB->Release(); g_pMesh->GetIndexBuffer(&pMeshSourceIB); g_pMeshIB->Lock( 0, 0, (void**)&pDst, 0 ); pMeshSourceIB->Lock( 0, 0, (void**)&pSrc, 0 ); memcpy( pDst, pSrc, g_dwNumFaces * 3 * sizeof(WORD)); g_pMeshIB->Unlock(); pMeshSourceIB->Unlock(); pMeshSourceIB->Release(); //// Done with the material buffer pD3DXMtrlBuffer->Release(); return S_OK; }
//------------------------------------------------------------------------------------------------ // Name: XMesh // Desc: Constructs the subset geometry for a D3DXMesh //------------------------------------------------------------------------------------------------ bool XMesh::buildGeometryFromD3DXMesh(LPD3DXMESH d3dxMesh, SubsetGeometry* subsetGeometry, DWORD subsets) { // Check parameters if (APP_ERROR(!d3dxMesh || !subsetGeometry)("Invalid parameter to XMesh::buildGeometryFromD3DXMesh")) return false; // Add a reference to the mesh to counteract freeing it at the end d3dxMesh->AddRef(); // Get the device LPDIRECT3DDEVICE9 pd3dDevice = NULL; d3dxMesh->GetDevice(&pd3dDevice); // If this mesh isn't already in the correct format, have D3D do the grunt work of // converting it. bool generate_normals = false; // Whether or not normals need to be generated for this mesh if ((d3dxMesh->GetFVF() != D3DFVF_GEOMETRYVERTEX) || (D3DFMT_GEOMETRYINDEX == D3DFMT_INDEX32) && ((d3dxMesh->GetOptions() & D3DXMESH_32BIT) == 0)) { // Holds the mesh when its converted to the correct format LPD3DXMESH pTemd3dxMesh = NULL; // Duplicate the loaded mesh into the format if (APP_ERROR(d3dxMesh->CloneMeshFVF( D3DXMESH_SYSTEMMEM | ((D3DFMT_GEOMETRYINDEX == D3DFMT_INDEX32) ? D3DXMESH_32BIT : 0), D3DFVF_GEOMETRYVERTEX, pd3dDevice, &pTemd3dxMesh)) ("XMesh couldn't convert the source geometry format")) { d3dxMesh->Release(); pd3dDevice->Release(); return false; } // Generate normals if they didn't exist generate_normals = ((d3dxMesh->GetFVF()&D3DFVF_NORMAL)!=D3DFVF_NORMAL && (D3DFMT_GEOMETRYINDEX&D3DFVF_NORMAL)!=D3DFVF_NORMAL); // Use this mesh instead d3dxMesh->Release(); d3dxMesh = pTemd3dxMesh; } // The mesh must have its attributes sorted before it can be converted to single strips { // Allocate an adjacency buffer DWORD faces = d3dxMesh->GetNumFaces(); DWORD* pAdjacency = new DWORD[faces * 3]; bool failed = false; if (APP_ERROR(FAILED(d3dxMesh->GenerateAdjacency(ADJACENCY_EPSILON, pAdjacency)))("Unable to generate the mesh adjacency")) failed = true; { // Clean up "bowties" in the mesh that prevent lighting from being calculated correctly LPD3DXMESH cleaned_mesh = NULL; DWORD* cleaned_adjacency = new DWORD[faces * 3]; LPD3DXBUFFER errors_and_warnings = NULL; if (!failed && APP_ERROR(FAILED(D3DXCleanMesh(D3DXCLEAN_BOWTIES, d3dxMesh, pAdjacency, &cleaned_mesh, cleaned_adjacency, &errors_and_warnings))) ("Failed to clean mesh")) { failed = true; if (errors_and_warnings) { DEBUG_ERROR("Mesh cleaning error: %s", (const char*)errors_and_warnings->GetBufferPointer()); } } SAFE_RELEASE(errors_and_warnings); // If we successfully cleaned the mesh, use the new mesh and new set of // adjacencies. Otherwise, just delete anything that was allocated and // keep the original. if (failed) { SAFE_DELETE_ARRAY(cleaned_adjacency); SAFE_RELEASE(cleaned_mesh); } else { SAFE_DELETE_ARRAY(pAdjacency); SAFE_RELEASE(d3dxMesh) pAdjacency = cleaned_adjacency; d3dxMesh = cleaned_mesh; } } // Compute mesh normals, if necessary if (!failed && generate_normals && APP_ERROR(FAILED(D3DXComputeNormals(d3dxMesh, pAdjacency)))("Couldn't generate mesh normals")) { failed = true; } // Optimize the mesh if (!failed && APP_ERROR(FAILED(d3dxMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, pAdjacency, NULL, NULL, NULL))) ("Couldn't optimize mesh attributes")) { failed = true; } // Get rid of the temporary adjacency buffer SAFE_DELETE_ARRAY(pAdjacency); // Return if there was an error if (failed) { SAFE_RELEASE(d3dxMesh); SAFE_RELEASE(pd3dDevice); return false; } } // Lock the vertex buffer GeometryVertex* pXVertices = NULL; if (APP_ERROR(d3dxMesh->LockVertexBuffer(D3DLOCK_READONLY, (VOID**)&pXVertices))("Couldn't lock source vertex buffer")) { // Erase this mesh d3dxMesh->Release(); pd3dDevice->Release(); // Failure return false; } // Iterate through all of the materials and copy vertex/index data, and assign material // information for the mesh. for (DWORD subset = 0; subset < subsets; subset++) { // Use D3DX to convert this subset into a nicely indexed form DWORD numStripIndices; LPDIRECT3DINDEXBUFFER9 pSubsetIB; if (APP_ERROR(D3DXConvertMeshSubsetToSingleStrip(d3dxMesh, subset, D3DXMESH_SYSTEMMEM, &pSubsetIB, &numStripIndices))("Couldn't convert mesh subset into indexable strip")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Return the error return false; } D3DINDEXBUFFER_DESC desc; GeometryIndex* pXIndices = NULL; // Check the format of the indices and lock the strip index buffer if (APP_ERROR(pSubsetIB->GetDesc(&desc))("Couldn't get .X mesh IB desc") || (desc.Format != D3DFMT_GEOMETRYINDEX) || APP_ERROR(pSubsetIB->Lock(0, 0, (VOID**)&pXIndices, D3DLOCK_READONLY))("Unable to lock the .X index buffer")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh pSubsetIB->Release(); d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Error! return false; } // This table pairs an index from the .X file to an index in the buffer that // holds the vertices for this subset XIndicesTable xIndicesTable; // For each of the indices in the strip, puts its vertex ID into the indices // table. Use the counter to determine which vertex this is. { GeometryIndex vertexCounter = 0; for (DWORD e = 0; e < numStripIndices; ++e) { // Insert the entry [x-mesh index, subset index] into the table XIndicesTableInsertResult result = xIndicesTable.insert(XIndicesEntry(pXIndices[e], vertexCounter)); // If the result was successful (this isn't a duplicated X-mesh index) increment the vertex counter if (result.second) vertexCounter++; } } // Grab the number of vertices this geometry uses DWORD numVertices = (DWORD)xIndicesTable.size(); // This buffer holds all of the triangles in this subset TriangleList triangles; // This list keeps track of locations in the strip where the winding order changes. This is necessary // because this next part will remove degenerate triangles from the list. std::set<size_t> windingChanges; // Generate the list of triangles from the strip provided for (DWORD t = 0; t < numStripIndices - 2; ++t) { // Build the triangle that will be added to the buffer // CHANGED July 25, 2008: the winding order is wrong here //Triangle tri = { pXIndices[t + 0], pXIndices[t + 1], pXIndices[t + 2] }; Triangle tri = { pXIndices[t + 0], pXIndices[t + 2], pXIndices[t + 1] }; // Convert the triangle into subset-indices by using the lookup table // we generated before. tri.index[0] = xIndicesTable.find(tri.index[0])->second; tri.index[1] = xIndicesTable.find(tri.index[1])->second; tri.index[2] = xIndicesTable.find(tri.index[2])->second; // Check to make sure this triangle isn't degenerate. If it is, we can just skip // this triangle entirely to simplify the geometry. if (tri.index[0] == tri.index[1] || tri.index[1] == tri.index[2] || tri.index[0] == tri.index[2]) { // Try to find the winding in the list std::set<size_t>::iterator currentWinding = windingChanges.find(triangles.size()); // Add this to the winding change list, or remove the change if it's already there if (currentWinding != windingChanges.end()) windingChanges.erase(currentWinding); else windingChanges.insert(triangles.size()); // Don't insert a triangle here continue; } // Add this triangle to the list triangles.push_back(tri); } // Calculate the number of indices we need for the buffer DWORD numGeometryIndices = (DWORD)(triangles.size() * 3); // Allocate the destination geometry Geometry* pGeometry = NULL; if (APP_ERROR(AllocateGeometry(numVertices, numGeometryIndices, &pGeometry))("Couldn't allocate geometry")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh pSubsetIB->Unlock(); pSubsetIB->Release(); d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Error! return false; } // Copy the vertices needed for this subset into the buffer GeometryVertex* pVertices = pGeometry->pVertices; for (XIndicesIterator i = xIndicesTable.begin(); i != xIndicesTable.end(); ++i) { GeometryVertex* pCurrentVertex = &pVertices[i->second]; *pCurrentVertex = pXVertices[i->first]; // Modify the vertex location to make this a unit mesh sitting on the X-Z plane pCurrentVertex->x = pCurrentVertex->x; pCurrentVertex->y = pCurrentVertex->y; pCurrentVertex->z = pCurrentVertex->z; //pVertices[i->second].color = D3DCOLOR_XRGB(255,255,255); // todo: enable color? } // Copy triangles into the indices buffer DWORD index = 0; GeometryIndex* pIndices = pGeometry->pIndices; DWORD windingOrder = 0; for (TriangleIterator t = triangles.begin(); t != triangles.end(); ++t) { // Find this index in the winding list if (windingChanges.find(index / 3) != windingChanges.end()) windingOrder = 1 - windingOrder; // Alternate the winding order so that everything shows up correctly if ((index / 3) % 2 == windingOrder) { pIndices[index + 0] = t->index[0]; pIndices[index + 1] = t->index[1]; pIndices[index + 2] = t->index[2]; } else { pIndices[index + 0] = t->index[1]; pIndices[index + 1] = t->index[0]; pIndices[index + 2] = t->index[2]; } // Increment the index counter index += 3; } // Unlock and delete strip index buffer pSubsetIB->Unlock(); pSubsetIB->Release(); // Store the buffers in the main array std::pair<SubsetGeometry::iterator,bool> result = subsetGeometry->insert(SubsetGeometry::value_type(subset, pGeometry)); if (APP_ERROR(!result.second)("Couldn't insert subset geometry into main array for .X mesh")) { // Get rid of this geometry DeallocateGeometry(pGeometry); DeallocateGeometry(subsetGeometry); // Erase the mesh d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Return error return false; } //DEBUG_MSG("Subset %i has %i vertices %i indices (%i polygons)\n", subset, numVertices, numGeometryIndices, numGeometryIndices / 3); } // Done with the DirectX mesh. This will not erase the outside mesh. d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free the device reference pd3dDevice->Release(); // Success return true; }
void CreateBox( const float &w, const float &h, const float &d, const bool ¢erWidth, const bool ¢erHeight, const bool ¢erDepth, LPD3DXMESH &mesh ) { float offsetX = 0, offsetY = 0, offsetZ = 0; if( centerWidth ) offsetX = -w / 2.f; if( centerHeight ) offsetY = -h / 2.f; if( centerDepth ) offsetZ = -d / 2.f; std::vector<DWORD> vIB; std::vector<VERTEX3> vVB; std::vector<DWORD> vAB; DWORD offset = 0; // fill in the front face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the front face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, 0.f + offsetZ, 0.f, 0.f, -1.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, 0.f + offsetZ, 0.f, 0.f, -1.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, 0.f + offsetZ, 0.f, 0.f, -1.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, 0.f + offsetZ, 0.f, 0.f, -1.f, 1.f, 1.f ) ); vAB.push_back( 0 ); vAB.push_back( 0 ); offset += 4; // fill in the back face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the back face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, d + offsetZ, 0.f, 0.f, 1.f, 1.f, 1.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, d + offsetZ, 0.f, 0.f, 1.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, d + offsetZ, 0.f, 0.f, 1.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, d + offsetZ, 0.f, 0.f, 1.f, 1.f, 0.f ) ); vAB.push_back( 1 ); vAB.push_back( 1 ); offset += 4; // fill in the top face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); //fill in the top face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, 0.f + offsetZ, 0.f, 1.f, 0.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, d + offsetZ, 0.f, 1.f, 0.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, d + offsetZ, 0.f, 1.f, 0.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, 0.f + offsetZ, 0.f, 1.f, 0.f, 1.f, 1.f ) ); vAB.push_back( 2 ); vAB.push_back( 2 ); offset += 4; // fill in the bottom face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the bottom face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, 0.f + offsetZ, 0.f, -1.f, 0.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, 0.f + offsetZ, 0.f, -1.f, 0.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, d + offsetZ, 0.f, -1.f, 0.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, d + offsetZ, 0.f, -1.f, 0.f, 1.f, 1.f ) ); vAB.push_back( 3 ); vAB.push_back( 3 ); offset += 4; // fill in the left face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the left face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, d + offsetZ, -1.f, 0.f, 0.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, d + offsetZ, -1.f, 0.f, 0.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, 0.f + offsetZ, -1.f, 0.f, 0.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, 0.f + offsetZ, -1.f, 0.f, 0.f, 1.f, 1.f ) ); vAB.push_back( 4 ); vAB.push_back( 4 ); offset += 4; // fill in the right face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the right face vertex data vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, 0.f + offsetZ, 1.f, 0.f, 0.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, 0.f + offsetZ, 1.f, 0.f, 0.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, d + offsetZ, 1.f, 0.f, 0.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, d + offsetZ, 1.f, 0.f, 0.f, 1.f, 1.f ) ); vAB.push_back( 5 ); vAB.push_back( 5 ); offset += 4; D3DXCreateMeshFVF( offset / 2, offset, D3DXMESH_MANAGED | D3DXMESH_32BIT, VERTEX3::FVF, g_pEngine->core->lpd3dd9, &mesh ); VERTEX3 *pVB = nullptr; mesh->LockVertexBuffer( D3DLOCK_DISCARD, reinterpret_cast< void** >( &pVB ) ); copy( vVB.begin(), vVB.end(), pVB ); mesh->UnlockVertexBuffer(); DWORD *pIB = nullptr; mesh->LockIndexBuffer( D3DLOCK_DISCARD, reinterpret_cast< void** >( &pIB ) ); copy( vIB.begin(), vIB.end(), pIB ); mesh->UnlockIndexBuffer(); DWORD *pAB = nullptr; mesh->LockAttributeBuffer( D3DLOCK_DISCARD, &pAB ); copy( vAB.begin(), vAB.end(), pAB ); mesh->UnlockAttributeBuffer(); std::vector<DWORD> adjacencyBuffer( mesh->GetNumFaces() * 3 ); mesh->GenerateAdjacency( 0.f, &adjacencyBuffer[ 0 ] ); mesh->OptimizeInplace( D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, &adjacencyBuffer[ 0 ], nullptr, nullptr, nullptr ); }
//----------------------------------------------------------------------------- // 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; }
//************************************************************************************************************* void GenerateEdges(edgeset& out, LPD3DXMESH mesh) { D3DXVECTOR3 p1, p2, p3; D3DXVECTOR3 a, b, n; Edge e; BYTE* vdata = 0; WORD* idata = 0; size_t ind; DWORD numindices = mesh->GetNumFaces() * 3; DWORD stride = mesh->GetNumBytesPerVertex(); WORD i1, i2, i3; bool is32bit = (mesh->GetOptions() & D3DXMESH_32BIT); out.clear(); if( is32bit ) { MYERROR("GenerateEdges(): 4 byte indices not implemented yet"); return; } // generate edge info mesh->LockIndexBuffer(D3DLOCK_READONLY, (LPVOID*)&idata); mesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&vdata); out.reserve(512); for( DWORD i = 0; i < numindices; i += 3 ) { if( out.capacity() <= out.size() ) out.reserve(out.size() + 1024); i1 = idata[i + 0]; i2 = idata[i + 1]; i3 = idata[i + 2]; p1 = *((D3DXVECTOR3*)(vdata + i1 * stride)); p2 = *((D3DXVECTOR3*)(vdata + i2 * stride)); p3 = *((D3DXVECTOR3*)(vdata + i3 * stride)); a = p2 - p1; b = p3 - p1; D3DXVec3Cross(&n, &a, &b); D3DXVec3Normalize(&n, &n); if( i1 < i2 ) { e.i1 = i1; e.i2 = i2; e.v1 = p1; e.v2 = p2; e.n1 = n; if( !out.insert(e) ) std::cout << "Crack in mesh (first triangle)\n"; } if( i2 < i3 ) { e.i1 = i2; e.i2 = i3; e.v1 = p2; e.v2 = p3; e.n1 = n; if( !out.insert(e) ) std::cout << "Crack in mesh (first triangle)\n"; } if( i3 < i1 ) { e.i1 = i3; e.i2 = i1; e.v1 = p3; e.v2 = p1; e.n1 = n; if( !out.insert(e) ) std::cout << "Crack in mesh (first triangle)\n"; } } // find second triangle for each edge for( DWORD i = 0; i < numindices; i += 3 ) { i1 = idata[i + 0]; i2 = idata[i + 1]; i3 = idata[i + 2]; p1 = *((D3DXVECTOR3*)(vdata + i1 * stride)); p2 = *((D3DXVECTOR3*)(vdata + i2 * stride)); p3 = *((D3DXVECTOR3*)(vdata + i3 * stride)); a = p2 - p1; b = p3 - p1; D3DXVec3Cross(&n, &a, &b); D3DXVec3Normalize(&n, &n); if( i1 > i2 ) { e.i1 = i2; e.i2 = i1; ind = out.find(e); if( ind == edgeset::npos ) { std::cout << "Lone triangle\n"; continue; } if( out[ind].other == 0xffffffff ) { out[ind].other = i / 3; out[ind].n2 = n; } else std::cout << "Crack in mesh (second triangle)\n"; } if( i2 > i3 ) { e.i1 = i3; e.i2 = i2; ind = out.find(e); if( ind == edgeset::npos ) { std::cout << "Lone triangle\n"; continue; } if( out[ind].other == 0xffffffff ) { out[ind].other = i / 3; out[ind].n2 = n; } else std::cout << "Crack in mesh (second triangle)\n"; } if( i3 > i1 ) { e.i1 = i1; e.i2 = i3; ind = out.find(e); if( ind == edgeset::npos ) { std::cout << "Lone triangle\n"; continue; } if( out[ind].other == 0xffffffff ) { out[ind].other = i / 3; out[ind].n2 = n; } else std::cout << "Crack in mesh (second triangle)\n"; } } mesh->UnlockIndexBuffer(); mesh->UnlockVertexBuffer(); }
//メッシュコンテナの生成 HRESULT Dx_Hierarchy::CreateMeshContainer( LPCTSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppMeshContainer ) { HRESULT hr = S_OK; //生成用オブジェクトの宣言 DxMeshContainer *pMeshContainer = NULL; //生成したオブジェクトの登録先を初期化 *ppMeshContainer = NULL; int iFacesAmount; unsigned iMaterial; LPDIRECT3DDEVICE9 pDevice = NULL; LPD3DXMESH pMesh = NULL; // patch meshes を扱う事はできない //if( pMeshData->Type != D3DXMESHTYPE_MESH ) return E_FAIL; // FVF で記述されたメッシュ以外は読めない //if( pMesh->GetFVF() == 0 ) return E_FAIL; //DWORD dwBoneAmt=0; //メッシュデータの持つメッシュポインタを取得 pMesh = pMeshData->pMesh; //オブジェクトの生成 pMeshContainer = new DxMeshContainer; //変数がNULLだった場合 if (pMeshContainer == NULL) { //エラーの意味 : Direct3D が呼び出しを完了するための十分なメモリを割り当てることができませんでした。 return E_OUTOFMEMORY; } // ZeroMemory(pMeshContainer, sizeof(DxMeshContainer)); //メッシュコンテナ名の領域確保 pMeshContainer->Name=new TCHAR[lstrlen(Name) + 1]; //領域が確保されなかった場合 if (!pMeshContainer->Name) { //エラーの意味 : Direct3D サブシステム内で原因不明のエラーが発生しました。 return E_FAIL; } //名前をコピーする strcpy(pMeshContainer->Name,Name); //メッシュに関連付けられているデバイスを取得 if(FAILED(pMesh->GetDevice(&pDevice))) { /*hr = E_FAIL; SAFE_RELEASE( pDevice ); if( pMeshContainer ) DestroyMeshContainer( pMeshContainer ); return hr;*/ } //メッシュに含まれる面の数を取得 iFacesAmount = pMesh->GetNumFaces(); // 当該メッシュが法線を持たない場合は法線を追加する if (!(pMesh->GetFVF() & D3DFVF_NORMAL)) { //メッシュデータの種類を「メッシュ」に変更 pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; //FVFコードを使ってメッシュのコピーを生成 hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pDevice, &pMeshContainer->MeshData.pMesh ); //処理が失敗した場合 if (FAILED(hr)) { //エラーの意味 : Direct3D サブシステム内で原因不明のエラーが発生しました。 return E_FAIL; } pMesh = pMeshContainer->MeshData.pMesh; //pMeshに含まれる各頂点の法線を計算して出力 D3DXComputeNormals( pMesh, NULL ); } else{ //メッシュコンテナ内のメッシュデータにメッシュポインタを設定 pMeshContainer->MeshData.pMesh = pMesh; //メッシュデータの種類を「メッシュ」に設定 pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; //??? pMesh->AddRef(); } //メッシュのマテリアル設定 //マテリアル数を設定 pMeshContainer->NumMaterials = max(1, NumMaterials); //マテリアルの数だけマテリアルの領域を確保 pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; //マテリアルの数だけテクスチャの領域確保 pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; //面の数だけ領域を確保 pMeshContainer->pAdjacency = new DWORD[iFacesAmount*3]; //それぞれの領域確保に失敗した場合 if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL)) { //エラーの意味 : Direct3D が呼び出しを完了するための十分なメモリを割り当てることができませんでした。 return E_OUTOFMEMORY; } //配列に0を設定 memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials); //配列にpAbjacencyを設定 memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * iFacesAmount*3); //マテリアルが存在する時 if (NumMaterials > 0) { // memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials); // for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++) { //テクスチャのファイル名が存在する場合 if( pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL) { //ファイルまでの相対パスを設定 char path[256] ="res/x/"; //ファイル名を取得 LPSTR fName = pMeshContainer->pMaterials[iMaterial].pTextureFilename; //テクスチャ情報の生成 pMeshContainer->ppTextures[iMaterial] = this->t_manager->LoadTextureFromFile(fName,path); //テクスチャ名の破棄 pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL; } } } else { //テクスチャ名の破棄 pMeshContainer->pMaterials[0].pTextureFilename = NULL; //マテリアルに0を設定 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(pSkinInfo!=NULL) { //メッシュコンテナ内のスキニング情報を設定 pMeshContainer->pSkinInfo = pSkinInfo; //??? pSkinInfo->AddRef(); //スキニング情報からボーンを生成 this->CreateBone(pMeshContainer,pDevice); } //ローカルに生成したメッシュコンテナを呼び出し側にコピーする *ppMeshContainer = pMeshContainer; //処理が無事に終了 return hr; }
HRESULT KG3DMesh::CreateBspFile() { HRESULT hrResult = E_FAIL; HRESULT hrRetCode = E_FAIL; int nRetCode = false; TCHAR szBSPPathName[MAX_PATH]; void *pvVerticesBuffer = NULL; WORD* pIndexBuffer = NULL; D3DXVECTOR3 *pPos = NULL; DWORD *pdwFaceIndex = NULL; DWORD dwStride = 0; DWORD i = 0; DWORD dwNumFaces = 0; DWORD dwNumVertices = 0; DWORD dwStartTime = timeGetTime(); LPD3DXMESH piMesh = m_ppMeshes[SMBT_NORMAL]; KG3DBsp *pBSP = NULL; KGLOG_PROCESS_ERROR(piMesh); dwStride = piMesh->GetNumBytesPerVertex(); dwNumVertices = piMesh->GetNumVertices(); dwNumFaces = piMesh->GetNumFaces(); KG_PROCESS_SUCCESS(dwNumFaces < 256); pPos = new D3DXVECTOR3[dwNumVertices]; KG_ASSERT_EXIT(pPos); pdwFaceIndex = new DWORD[dwNumFaces * 3]; KG_ASSERT_EXIT(pdwFaceIndex); hrRetCode = piMesh->LockVertexBuffer(D3DLOCK_READONLY, (void **)&pvVerticesBuffer); KGLOG_COM_PROCESS_ERROR(hrRetCode); hrRetCode = piMesh->LockIndexBuffer(D3DLOCK_READONLY, (void **)&pIndexBuffer); KGLOG_COM_PROCESS_ERROR(hrRetCode); for (i = 0; i < dwNumVertices; ++i) { pPos[i] = *(D3DXVECTOR3 *)(((BYTE *)pvVerticesBuffer) + dwStride * i); } for (i = 0; i < dwNumFaces * 3; ++i) { pdwFaceIndex[i] = pIndexBuffer[i]; } // -------------------------- create BSP -------------------------- hrRetCode = ChangePathExtName(m_scName.c_str(), "bsp", sizeof(szBSPPathName), szBSPPathName); KGLOG_COM_PROCESS_ERROR(hrRetCode); pBSP = new KG3DBsp; KGLOG_PROCESS_ERROR(pBSP); hrRetCode = pBSP->CreateFromMesh(dwNumVertices, dwNumFaces, pPos, pdwFaceIndex); KGLOG_COM_PROCESS_ERROR(hrRetCode); hrRetCode = pBSP->SaveToFile(szBSPPathName); KGLOG_COM_PROCESS_ERROR(hrRetCode); DWORD dwCost = timeGetTime() - dwStartTime; if(dwCost > 500) { KGLogPrintf( KGLOG_WARNING, "BSP %d %d Face %s", dwCost, dwNumFaces, szBSPPathName ); } KG_DELETE(m_lpBsp); // recreate m_lpBsp = pBSP; pBSP = NULL; Exit1: hrResult = S_OK; Exit0: KG_DELETE(pBSP); if (pIndexBuffer) { piMesh->UnlockIndexBuffer(); pIndexBuffer = NULL; } if (pvVerticesBuffer) { piMesh->UnlockVertexBuffer(); pvVerticesBuffer = NULL; } KG_DELETE_ARRAY(pdwFaceIndex); KG_DELETE_ARRAY(pPos); if(FAILED(hrResult)) { KGLogPrintf(KGLOG_ERR, "%s 创建失败", szBSPPathName); } return hrResult; }
//----------------------------------------------------------------------------- // Name: buildShadowVolume() // Desc: Takes a mesh as input, and uses it to build a shadow volume. The // technique used considers each triangle of the mesh, and adds it's // edges to a temporary list. The edge list is maintained, such that // only silohuette edges are kept. Finally, the silohuette edges are // extruded to make the shadow volume vertex list. //----------------------------------------------------------------------------- HRESULT CShadowVolume::BuildShadowVolume(LPD3DXMESH pMesh, D3DXVECTOR3 vLight) { // pMesh的顶点结构 struct MeshVertex { D3DXVECTOR3 p; D3DXVECTOR3 n; float u, v; }; MeshVertex *pVertices; WORD *pIndices; // 锁缓存 pMesh->LockVertexBuffer(0L, (LPVOID*)&pVertices); pMesh->LockIndexBuffer(0L, (LPVOID*)&pIndices); DWORD dwNumFaces = pMesh->GetNumFaces(); // 分配一个临时的索引数组 WORD *pEdges = new WORD[dwNumFaces * 6]; if (pEdges == NULL) { pMesh->UnlockVertexBuffer(); pMesh->UnlockIndexBuffer(); return E_OUTOFMEMORY; } DWORD dwNumEdges = 0; // 对每个片面进行计算 for (DWORD i = 0; i < dwNumFaces; ++i) { WORD wFace0 = pIndices[3 * i + 0]; WORD wFace1 = pIndices[3 * i + 1]; WORD wFace2 = pIndices[3 * i + 2]; // 一个面的三个顶点坐标 D3DXVECTOR3 v0 = pVertices[wFace0].p; D3DXVECTOR3 v1 = pVertices[wFace1].p; D3DXVECTOR3 v2 = pVertices[wFace2].p; // 计算法线是否向光 D3DXVECTOR3 vCross1(v2 - v1); D3DXVECTOR3 vCross2(v1 - v0); D3DXVECTOR3 vNormal; D3DXVec3Cross(&vNormal, &vCross1, &vCross2); if (D3DXVec3Dot(&vNormal, &vLight) >= 0.0f) { AddEdge(pEdges, dwNumEdges, wFace0, wFace1); AddEdge(pEdges, dwNumEdges, wFace1, wFace2); AddEdge(pEdges, dwNumEdges, wFace2, wFace0); } } // pEdges中仅剩pMesh的边缘顶点,对每条边的两个顶点按光照的方向进行延伸 // 最终构建一个完整的阴影体 for (DWORD i = 0; i < dwNumEdges; ++i) { D3DXVECTOR3 v1 = pVertices[pEdges[2 * i + 0]].p; D3DXVECTOR3 v2 = pVertices[pEdges[2 * i + 1]].p; D3DXVECTOR3 v3 = v1 + vLight * 200; D3DXVECTOR3 v4 = v2 + vLight * 200; // 封边操作 m_pVertices[m_dwNumVertices++] = v1; m_pVertices[m_dwNumVertices++] = v2; m_pVertices[m_dwNumVertices++] = v3; m_pVertices[m_dwNumVertices++] = v2; m_pVertices[m_dwNumVertices++] = v4; m_pVertices[m_dwNumVertices++] = v3; } // Delete the temporary edge list delete[] pEdges; // Unlock the geometry buffers pMesh->UnlockVertexBuffer(); pMesh->UnlockIndexBuffer(); return S_OK; }
void optimizePhysXMesh(int flag, IDirect3DDevice9* D3DDevice, float epsilon, std::vector<physx::PxVec3>& pxVertices, oiram::IndexBuffer& indexBuffer) { assert(D3DDevice); D3DVERTEXELEMENT9 szDecl[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, {0xFF, 0, D3DDECLTYPE_UNUSED, 0, 0, 0} }; // 创建D3D MESH LPD3DXMESH pMesh = 0; DWORD options = D3DXMESH_SYSTEMMEM | D3DXMESH_DYNAMIC; if (indexBuffer.use32BitIndices) options |= D3DXMESH_32BIT; DWORD numVertices = static_cast<DWORD>(pxVertices.size()), numFaces = numVertices / 3; HRESULT hr = D3DXCreateMesh(numFaces, numVertices, options, szDecl, D3DDevice, &pMesh); if (SUCCEEDED(hr)) { LPVOID pData = nullptr; // 填充Index Buffer if (SUCCEEDED(pMesh->LockIndexBuffer(D3DLOCK_DISCARD, &pData))) { if (indexBuffer.use32BitIndices) memcpy(pData, indexBuffer.uiIndexBuffer.data(), indexBuffer.uiIndexBuffer.size() * sizeof(physx::PxU32)); else memcpy(pData, indexBuffer.usIndexBuffer.data(), indexBuffer.usIndexBuffer.size() * sizeof(physx::PxU16)); pMesh->UnlockIndexBuffer(); } // 填充Vertex Buffer if (SUCCEEDED(pMesh->LockVertexBuffer(D3DLOCK_DISCARD, &pData))) { memcpy(pData, pxVertices.data(), pxVertices.size() * sizeof(physx::PxVec3)); pMesh->UnlockVertexBuffer(); } // 进行Mesh优化 DWORD dwFaces = pMesh->GetNumFaces(); std::vector<DWORD> szAdjacencies(dwFaces * 3); DWORD* pAdjacency = &szAdjacencies[0]; pMesh->GenerateAdjacency(epsilon, pAdjacency); // 清理mesh hr = D3DXCleanMesh(D3DXCLEAN_SIMPLIFICATION, pMesh, pAdjacency, &pMesh, pAdjacency, NULL); if (SUCCEEDED(hr)) { // 去除mesh中重复的顶点 hr = D3DXWeldVertices(pMesh, D3DXWELDEPSILONS_WELDALL, NULL, pAdjacency, pAdjacency, NULL, NULL); if (SUCCEEDED(hr)) { // 将优化后的数据写回mesh data DWORD numIndices = pMesh->GetNumFaces() * 3; indexBuffer.use32BitIndices = numIndices > 65535; if (indexBuffer.use32BitIndices) indexBuffer.uiIndexBuffer.resize(numIndices); else indexBuffer.usIndexBuffer.resize(numIndices); // 取出Index Buffer if (SUCCEEDED(pMesh->LockIndexBuffer(D3DLOCK_READONLY | D3DLOCK_DISCARD, &pData))) { if (indexBuffer.use32BitIndices) memcpy(indexBuffer.uiIndexBuffer.data(), pData, indexBuffer.uiIndexBuffer.size() * sizeof(physx::PxU32)); else memcpy(indexBuffer.usIndexBuffer.data(), pData, indexBuffer.usIndexBuffer.size() * sizeof(physx::PxU16)); pMesh->UnlockIndexBuffer(); } // 取出Vertex Buffer DWORD dwVertices = pMesh->GetNumVertices(); pxVertices.resize(dwVertices); if (SUCCEEDED(pMesh->LockVertexBuffer(D3DLOCK_READONLY | D3DLOCK_DISCARD, &pData))) { memcpy(pxVertices.data(), pData, pxVertices.size() * sizeof(physx::PxVec3)); pMesh->UnlockVertexBuffer(); } } } pMesh->Release(); } }
DWORD MeshParameterization::OnGenerateAtlas( DWORD size, void * params ) { VERIFY_MESSAGE_SIZE( size, sizeof( GENERATEATLASMESSAGE ) ); GENERATEATLASMESSAGE * msg = (GENERATEATLASMESSAGE*)params; if( !msg ) { return MSG_ERROR; } bool bUseIncomingTexCoords = msg->useIncomingTexCoords; GenerateBounds(); HRESULT hr; //This should be changed to use a new mesh parameterization technique DWORD numFaces = (DWORD)m_Faces->size(); DWORD numVertices = (DWORD)m_CollapsedMesh->size(); DWORD curError = 0; if( !bUseIncomingTexCoords && numFaces > 0 && numVertices > 0 ) { DWORD fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 ; DWORD flags = D3DXMESH_SYSTEMMEM ;// | D3DXMESH_MANAGED ;// | D3DXMESH_SOFTWAREPROCESSING | D3DXMESH_SYSTEMMEM |; LPD3DXMESH mesh = NULL; hr = D3DXCreateMeshFVF( numFaces, numVertices, flags, fvf, m_pDevice, &mesh ); if( FAILED( hr ) ) { curError = GetLastError(); EngineGetToolBox()->Log(LOGERROR, _T("MeshParameterization: Error in create mesh fvf\n")); return MSG_ERROR; } //now fill with data BYTE * vertexData; BYTE * indexData; hr = mesh->LockVertexBuffer( 0, (LPVOID*)&vertexData ); hr = mesh->LockIndexBuffer( 0, (LPVOID*)&indexData ); D3DVERTEXELEMENT9 Decl[ MAX_FVF_DECL_SIZE ]; mesh->GetDeclaration( Decl ); paramVertex * pVertOriginal = (paramVertex*)vertexData; for( int i = 0; i < (int)numVertices; i++ ) { paramVertex * pVert = (paramVertex*)vertexData; pVert->x = (*m_CollapsedMesh)[i].originalPosition.x; pVert->y = (*m_CollapsedMesh)[i].originalPosition.y; pVert->z = (*m_CollapsedMesh)[i].originalPosition.z; pVert->nx = -(*m_CollapsedMesh)[i].normal.x; pVert->ny = -(*m_CollapsedMesh)[i].normal.y; pVert->nz = -(*m_CollapsedMesh)[i].normal.z; pVert->u = (*m_CollapsedMesh)[i].generatedU; pVert->v = (*m_CollapsedMesh)[i].generatedV; NormalizeUV( pVert->u ); NormalizeUV( pVert->v ); vertexData += sizeof( paramVertex ); } for( int i = 0; i < (int)numFaces; i++ ) { unsigned short * index = (unsigned short*)indexData; index[0] = ( unsigned short )(*m_Faces)[ i ].index[ 0 ]; index[1] = ( unsigned short )(*m_Faces)[ i ].index[ 1 ]; index[2] = ( unsigned short )(*m_Faces)[ i ].index[ 2 ]; indexData += sizeof( unsigned short )*3;//32 bit indices triangles } LPD3DXBUFFER imt; hr = D3DXComputeIMTFromPerVertexSignal( mesh, (const float*)pVertOriginal + 3*sizeof(float), 3, sizeof(paramVertex), 0L, 0, 0, &imt ); mesh->UnlockIndexBuffer(); mesh->UnlockVertexBuffer(); //tensors float * tensors = new float[ 3*numFaces ]; for( int i = 0; i < 3*(int)numFaces; i += 3 ) { tensors[ i ] = 4.f; tensors[ i + 1 ] = 0.f; tensors[ i + 2 ] = 4.f; } //some checks numVertices = mesh->GetNumVertices(); numFaces = mesh->GetNumFaces(); //create adjacency DWORD * adjacency = new DWORD[ 3*numFaces ]; memset( adjacency, 0, sizeof(DWORD)*3*numFaces ); hr = mesh->GenerateAdjacency( 0.001f, adjacency ); //hr = mesh->ConvertPointRepsToAdjacency( NULL, adjacency ); if( FAILED( hr ) ) { curError = GetLastError(); EngineGetToolBox()->Log(LOGERROR, _T("MeshParameterization: Error in generate adjacency\n")); return MSG_ERROR; } /* save to mesh to check model uvs D3DXMATERIAL mat; mat.MatD3D.Ambient.r = mat.MatD3D.Ambient.a =mat.MatD3D.Ambient.b =mat.MatD3D.Ambient.g = 0; mat.MatD3D.Diffuse.r = mat.MatD3D.Diffuse.a =mat.MatD3D.Diffuse.b =mat.MatD3D.Diffuse.g = 1; mat.pTextureFilename = "tex.dds"; D3DXSaveMeshToX( "mesh.x", mesh, adjacency, &mat, NULL, 0, D3DXF_FILEFORMAT_TEXT ); */ float * imtTensor = tensors;//(float*)imt->GetBufferPointer(); float stretchout; unsigned int charts; LPD3DXMESH meshOut = NULL; LPD3DXBUFFER remappedData = NULL; LPD3DXBUFFER faceData = NULL; D3DXATTRIBUTERANGE Attrib; memset(&Attrib, 0, sizeof(D3DXATTRIBUTERANGE)); Attrib.FaceCount = numFaces; Attrib.VertexCount = numVertices; mesh->SetAttributeTable(&Attrib, 1); int gutter = m_TexSize / 32; gutter = min( gutter, 6 ); hr = D3DXUVAtlasCreate( mesh, 0, .5, m_TexSize, m_TexSize, 6, //gutter 0, adjacency, 0, imtTensor, (LPD3DXUVATLASCB)UVGenCallback, .0001f, 0, //D3DXUVATLAS_GEODESIC_QUALITY , D3DXUVATLAS_GEODESIC_FAST, &meshOut, &faceData, &remappedData, &stretchout, &charts ); if( FAILED( hr ) ) { curError = GetLastError(); EngineGetToolBox()->Log(LOGERROR, _T("MeshParameterization: Error in uv atlas create\n")); return MSG_ERROR; } /* save to mesh to check model uvs hr = meshOut->ConvertPointRepsToAdjacency( NULL, adjacency ); D3DXSaveMeshToX( "mesh2.x", meshOut, adjacency, &mat, NULL, 0, D3DXF_FILEFORMAT_TEXT ); */ delete [] adjacency; delete [] tensors; //Generate our lightmap cache data for passing on and saving GenerateCache( meshOut, remappedData ); GenerateTriangleTexelData(); meshOut->Release(); faceData->Release(); remappedData->Release(); mesh->Release(); } else if( bUseIncomingTexCoords ) { GenerateCache(); GenerateTriangleTexelData(); } return MSG_HANDLED_STOP; }