// Calculate T&B void OGF::CalculateTB() { remove_isolated_verts( data.vertices, data.faces ); // ************************************* Declare inputs Status ( "Declarator..." ); u32 v_count_reserve = iFloor( float( data.vertices.size() )*1.33f ); u32 i_count_reserve = 3*data.faces.size(); mender_mapping_out_to_in_vert .clear( ); mender_mapping_out_to_in_vert .reserve( v_count_reserve ); mender_in_out_verts .reserve( v_count_reserve ); mender_in_out_indices .reserve( i_count_reserve ); mender_in_out_verts .clear( ); mender_in_out_indices .clear( ); fill_mender_input( data.vertices, data.faces, mender_in_out_verts, mender_in_out_indices ); u32 v_was = data.vertices.size(); u32 v_become= mender_in_out_verts.size(); clMsg ("duplication: was[%d] / become[%d] - %2.1f%%",v_was,v_become,100.f*float(v_become-v_was)/float(v_was)); // ************************************* Perform mungle Status ("Calculating basis..."); MeshMender mender ; if ( !mender.Mend ( mender_in_out_verts, mender_in_out_indices, mender_mapping_out_to_in_vert, 1, 0.5, 0.5, 0.0f, MeshMender::DONT_CALCULATE_NORMALS, MeshMender::RESPECT_SPLITS, MeshMender::DONT_FIX_CYLINDRICAL ) ) { xrDebug::Fatal (DEBUG_INFO, "NVMeshMender failed " ); //xrDebug::Fatal (DEBUG_INFO,"NVMeshMender failed (%s)",mender.GetLastError().c_str()); } // ************************************* Bind declarators // bind retrive_data_from_mender_otput( data.vertices, data.faces, mender_in_out_verts, mender_in_out_indices, mender_mapping_out_to_in_vert ); remove_isolated_verts( data.vertices, data.faces ); mender_in_out_verts .clear( ); mender_in_out_indices .clear( ); mender_mapping_out_to_in_vert .clear( ); }
//------------------------------------------------------------------------------------------------------- bool Exporter::computeTangentSpace() { uint32_t numFaces = faces_.getSize(); std::vector<unsigned int> newFaces; newFaces.reserve(3 * numFaces); vertices_.reserve(numVertices_); for(uint32_t i = 0; i < numVertices_; ++i) vertices_.push_back(MeshMender::Vertex()); for(uint32_t i = 0; i < numFaces; ++i) { const RawMesh::Face& face = rawMesh_->faces_[i]; const RawMesh::Face& normalFace = rawMesh_->normalFaces_[i]; const RawMesh::Face& textureFace = rawMesh_->textureFaces_[i]; for(uint8_t j = 0; j < 3; ++j) { uint32_t vertexIndex = faces_[i].indices[j]; newFaces.push_back(vertexIndex); MeshMender::Vertex& vertex = vertices_[vertexIndex]; const auto& position = rawMesh_->positions_[face.indices[j]]; const auto& normal = rawMesh_->normals_[normalFace.indices[j]]; const auto& textureCoordinates = rawMesh_->textureCoordinates_[textureFace.indices[j]]; vertex.pos = position; vertex.normal = normal; vertex.s = textureCoordinates.x; vertex.t = textureCoordinates.y; } } MeshMender meshMender; if(!meshMender.Mend(vertices_, newFaces, newToOldVertexMapping_, 0.0f, 0.0f, 0.0f, 1.0f, MeshMender::DONT_CALCULATE_NORMALS)) return false; numVertices_ = vertices_.size(); for(uint32_t i = 0; i < numFaces; ++i) { for(uint8_t j = 0; j < 3; ++j) faces_[i].indices[j] = newFaces[3 * i + j]; } return true; }
void TriBaseSurface::prepare(TangentSpaceMode tangentSpaceMode) { if (tangentSpaceMode == TangentSpaceMode_MeshMender) { std::vector<MeshMender::Vertex> vertices; const uint vertexCount = m_mesh->vertexCount(); vertices.resize(vertexCount); for (uint i = 0; i < vertexCount; i++) { const TriMesh::Vertex & vertex = m_mesh->vertexAt(i); vertices[i].pos = vertex.pos; vertices[i].normal = vertex.nor; vertices[i].s = vertex.tex.x(); vertices[i].t = vertex.tex.y(); vertices[i].tangent = Vector3(zero); vertices[i].binormal = Vector3(zero); } std::vector<unsigned int> indices; const uint faceCount = m_mesh->faceCount(); indices.resize(3 * faceCount); for (uint i = 0; i < faceCount; i++) { const TriMesh::Face & face = m_mesh->faceAt(i); indices[3 * i + 0] = face.v[0]; indices[3 * i + 1] = face.v[1]; indices[3 * i + 2] = face.v[2]; } std::vector<unsigned int> xrefs; // Default options. float minNormalsCreaseCosAngle = 0.0f; float minTangentsCreaseCosAngle = 0.0f; float minBinormalsCreaseCosAngle = 0.0f; float weightNormalsByArea = 1.0f; MeshMender::NormalCalcOption computeNormals = MeshMender::CALCULATE_NORMALS; MeshMender::ExistingSplitOption respectExistingSplits = MeshMender::DONT_RESPECT_SPLITS; MeshMender::CylindricalFixOption fixCylindricalWrapping = MeshMender::DONT_FIX_CYLINDRICAL; MeshMender mender; mender.Mend(vertices, indices, xrefs, minNormalsCreaseCosAngle, minTangentsCreaseCosAngle, minBinormalsCreaseCosAngle, weightNormalsByArea, computeNormals, respectExistingSplits, fixCylindricalWrapping); // Create new triMesh. const uint newFaceCount = indices.size() / 3; const uint newVertexCount = vertices.size(); TriMesh * triMesh = new TriMesh(newFaceCount, newVertexCount); triMesh->faces().resize(newFaceCount); triMesh->vertices().resize(newVertexCount); m_basisArray.resize(newVertexCount); for (uint i = 0; i < newVertexCount; i++) { TriMesh::Vertex & vertex = triMesh->vertexAt(i); vertex.pos = vertices[i].pos; vertex.nor = vertices[i].normal; vertex.tex = Vector2(vertices[i].s, vertices[i].t); m_basisArray[i].normal = vertices[i].normal; m_basisArray[i].tangent = vertices[i].tangent; m_basisArray[i].bitangent = vertices[i].binormal; } for (uint i = 0; i < newFaceCount; i++) { TriMesh::Face & face = triMesh->faceAt(i); face.v[0] = indices[3 * i + 0]; face.v[1] = indices[3 * i + 1]; face.v[2] = indices[3 * i + 2]; } } else if (tangentSpaceMode == TangentSpaceMode_Lengyel) { if (!MeshNormals::hasNormals(m_mesh.ptr())) { MeshNormals::computeNormals(m_mesh.ptr(), WeightFaceArea); } geometry::computeMeshTangents(m_mesh.ptr(), m_basisArray); foreach(i, m_basisArray) { Basis & basis = m_basisArray[i]; // basis.orthonormalize(); UE3_CreateOrthonormalBasis(basis); } }
void C3DMeshModelBuilder::CalculateTangentSpace() { std::vector< MeshMender::Vertex > theVerts; std::vector< unsigned int > theIndices; std::vector< unsigned int > mappingNewToOld; // put indexed triangle polygons into a single index array std::vector<IndexedPolygon>& polygon_buffer = m_vecTriangulatedPolygon; size_t i, iNumTriangles = polygon_buffer.size(); theIndices.reserve( iNumTriangles * 3 ); for( i=0; i<iNumTriangles; i++ ) { IndexedPolygon& triangle = polygon_buffer[i]; assert( triangle.m_index.size() == 3 ); theIndices.push_back( triangle.m_index[0] ); theIndices.push_back( triangle.m_index[1] ); theIndices.push_back( triangle.m_index[2] ); } // fill up the vectors with your mesh's data std::vector<General3DVertex>& vert_buffer = *m_pMesh->GetVertexBuffer().get(); size_t iNumVertices = vert_buffer.size(); for( i = 0; i < iNumVertices; ++i ) { MeshMender::Vertex v; v.pos = vert_buffer[i].m_vPosition; v.s = vert_buffer[i].m_TextureCoord[0].u; v.t = vert_buffer[i].m_TextureCoord[0].v; v.normal = vert_buffer[i].m_vNormal; // meshmender will computer normals, tangents, and binormals, no need to fill those in. // however, if you do not have meshmender compute the normals, you _must_ pass in valid // normals to meshmender theVerts.push_back(v); } MeshMender mender; size_t iNumIndices = theIndices.size(); // pass it in to the mender to do it's stuff bool res = mender.Mend( theVerts, theIndices, mappingNewToOld, -1.0f, // minNormalCreaseCos -1.0f, // minTangentCreaseCos -1.0f, // minBinormalCreaseCos 0.0f, // weightNormalsByArea MeshMender::DONT_CALCULATE_NORMALS, MeshMender::RESPECT_SPLITS ); if( !res ) LOG_PRINT_WARNING( "MeshMender::Mend() failed." ); // check indices assert( iNumIndices == theIndices.size() ); // update vertices // new vertices may have been created and added to 'theVerts' by mesh mender size_t iNumUpdatedVertices = theVerts.size(); vector<General3DVertex> vecNewVertexBuffer; // temporary vertex buffer to hold new vertices vecNewVertexBuffer.resize( iNumUpdatedVertices ); for( i=0; i<iNumUpdatedVertices; ++i ) { vecNewVertexBuffer[i] = vert_buffer[ mappingNewToOld[i] ]; vecNewVertexBuffer[i].m_vNormal = theVerts[i].normal; vecNewVertexBuffer[i].m_vBinormal = theVerts[i].binormal; vecNewVertexBuffer[i].m_vTangent = theVerts[i].tangent; } // copy vertices to the original vertex buffer vert_buffer.clear(); vert_buffer.reserve( iNumUpdatedVertices ); vert_buffer = vecNewVertexBuffer; // update indices int vertex_index = 0; for( i=0; i<iNumTriangles; ++i ) { IndexedPolygon& triangle = polygon_buffer[i]; triangle.m_index[0] = theIndices[vertex_index++]; triangle.m_index[1] = theIndices[vertex_index++]; triangle.m_index[2] = theIndices[vertex_index++]; } }
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; }