#include #include "SimplificationMethod.h" #include #include #include #include "quadrics.h" using namespace std; using namespace Geometry; using namespace simplif; //------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------- SimplificationMethod::SimplificationMethod(const Mesh *m) { mInitialMesh = new Mesh(); *mInitialMesh = *m; mGeoMesh = NULL; first_index_submesh = new unsigned int[mInitialMesh->mSubMeshCount]; indexMeshLeaves = -1; // Create simplification sequence. msimpseq = new MeshSimplificationSequence(); } //------------------------------------------------------------------------- // Destructor //------------------------------------------------------------------------- SimplificationMethod::~SimplificationMethod() { delete heap; delete [] first_index_submesh; delete mInitialMesh; } //------------------------------------------------------------------------- // Recalculate the cost of the vertices of an edge //------------------------------------------------------------------------- void SimplificationMethod::compute_pair_info(simplif::pair_info *auxpair) { simplif::Vertex *v0 = auxpair->v0; simplif::Vertex *v1 = auxpair->v1; simplif::vert_info *v0_info = vertex_info(v0); simplif::vert_info *v1_info = vertex_info(v1); simplif::Mat4 Q = v0_info->Q + v1_info->Q; simplif::real norm = v0_info->norm + v1_info->norm; auxpair->cost = simplif::quadrix_pair_target( Q, v0, v1, auxpair->candidate); if ( simplif::will_weight_by_area ) { auxpair->cost /= norm; } if ( simplif::will_preserve_mesh_quality ) { auxpair->cost += pair_mesh_penalty(M0, v0, v1, auxpair->candidate); } // // NOTICE: In the heap we use the negative cost. That's because // the heap is implemented as a MAX heap. // if ( auxpair->isInHeap() ) { heap->update(auxpair, (float)-auxpair->cost); } else { heap->insert(auxpair, (float)-auxpair->cost); } } //------------------------------------------------------------------------- // Reasign the new vertex to the adequate face //------------------------------------------------------------------------- int SimplificationMethod::predict_face( simplif::Face& F, simplif::Vertex *v1, simplif::Vertex *v2, simplif::Vec3& vnew, simplif::Vec3& f1, simplif::Vec3& f2, simplif::Vec3& f3) { int nmapped = 0; if ( F.vertex(0) == v1 || F.vertex(0) == v2 ) { f1 = vnew; nmapped++; } else { f1 = *F.vertex(0); } if ( F.vertex(1) == v1 || F.vertex(1) == v2 ) { f2 = vnew; nmapped++; } else { f2 = *F.vertex(1); } if ( F.vertex(2) == v1 || F.vertex(2) == v2 ) { f3 = vnew; nmapped++; } else { f3 = *F.vertex(2); } return nmapped; } #define MESH_INVERSION_PENALTY 1e9 //------------------------------------------------------------------------- //------------------------------------------------------------------------- simplif::real SimplificationMethod::pair_mesh_penalty(simplif::Model& M, simplif::Vertex *v1, simplif::Vertex *v2, simplif::Vec3& vnew) { static simplif::face_buffer changed; changed.reset(); M.contractionRegion(v1, v2, changed); // real Nsum = 0; simplif::real Nmin = 0; for (int i = 0; i < changed.length(); i++) { simplif::Face& F = *changed(i); simplif::Vec3 f1, f2, f3; int nmapped = predict_face(F, v1, v2, vnew, f1, f2, f3); // Only consider non-degenerate faces if( nmapped < 2 ) { simplif::Plane Pnew(f1, f2, f3); simplif::real delta = Pnew.normal() * F.plane().normal(); if( Nmin > delta ) { Nmin = delta; } } } //return (-Nmin) * MESH_INVERSION_PENALTY; if( Nmin < 0.0 ) { return MESH_INVERSION_PENALTY; } else { return 0.0; } } //------------------------------------------------------------------------- // Returns true if the givens vertices are a valid pair //------------------------------------------------------------------------- bool SimplificationMethod::check_for_pair(simplif::Vertex *v0, simplif::Vertex *v1) { const simplif::pair_buffer& pairs = vertex_info(v0)->pairs; for(int i=0; iv0==v1 || pairs(i)->v1==v1 ) { return true; } } return false; } //------------------------------------------------------------------------- // Create a new pair with two given vertices //------------------------------------------------------------------------- simplif::pair_info *SimplificationMethod::new_pair( simplif::Vertex *v0, simplif::Vertex *v1) { simplif::pair_info *pair = new simplif::pair_info(v0,v1); simplif::vert_info *v0_info = vertex_info(v0); v0_info->pairs.add(pair); simplif::vert_info *v1_info = vertex_info(v1); v1_info->pairs.add(pair); return pair; } //------------------------------------------------------------------------- // Remove a given pair //------------------------------------------------------------------------- void SimplificationMethod::delete_pair(simplif::pair_info *auxpair) { simplif::vert_info *v0_info = vertex_info(auxpair->v0); simplif::vert_info *v1_info = vertex_info(auxpair->v1); v0_info->pairs.remove(v0_info->pairs.find(auxpair)); v1_info->pairs.remove(v1_info->pairs.find(auxpair)); if (auxpair->isInHeap()) { heap->kill(auxpair->getHeapPos()); } delete auxpair; } //------------------------------------------------------------------------- // Contract a given pair //------------------------------------------------------------------------- void SimplificationMethod::do_contract( simplif::Model &m, simplif::pair_info *auxpair, int obligatory) { simplif::Vertex *v0 = auxpair->v0; simplif::Vertex *v1 = auxpair->v1; simplif::Vec3 vnew = auxpair->candidate; float x,y,z; simplif::Vertex *aux_vert; _float3_ removed_vert; int i; vertex_map_str lb; vertex_map_str ub; // Stores the simplification step. MeshSimplificationSequence::Step simplifstep; // V0 must be always the alive vertex // V1 must be always the removed vertex if (vnew == (*v0)) { // Coords of the removed vertex. x = (*v1)[X]; y = (*v1)[Y]; z = (*v1)[Z]; aux_vert = v1; } else { // Coords of the removed vertex. x = (*v0)[X]; y = (*v0)[Y]; z = (*v0)[Z]; // Simplification step. aux_vert = v0; v0 = v1; v1 = aux_vert; } simplif::vert_info *v0_info = vertex_info(v0); simplif::vert_info *v1_info = vertex_info(v1); // Simplification step. simplifstep.mV0 = v0->vID; simplifstep.mV1 = v1->vID; // Position of the vertex removed. removed_vert = _float3_(x,y,z); // If position of the removed vertex is found. if (vertexMultimap.end() != vertexMultimap.find(removed_vert)) { lb = vertexMultimap.lower_bound(removed_vert); ub = vertexMultimap.upper_bound(removed_vert); // For each vertex. while (lb != ub) { // If removed vertex is found. if ((*lb).second == aux_vert->vID) { // Debug. cout << "to remove: " << (*lb).second << endl; // Delete vertex that disappears. vertexMultimap.erase(lb); // Break while. lb = ub; } else { // Next iteration. lb++; } } } // Make v0 be the new vertex v0_info->Q += v1_info->Q; v0_info->norm += v1_info->norm; simplif::Vec3 p(vnew); // Perform the actual contraction. static simplif::face_buffer changed; changed.reset(); m.contract(v0, v1, vnew, changed); // Stores the displacement in the simplification step. simplifstep.x = (float)0.0f; simplifstep.y = (float)0.0f; simplifstep.z = (float)0.0f; // Number of triangles that are removed in this simplification step. int _numDelTris = 0; // 1 or 2 triangles can be removed. for (i = 0; i < changed.length(); i++) { if (!changed(i)->isValid()) { _numDelTris++; } } int del_index = 0; // Initialize deleted triangles. simplifstep.mT0 = -1; simplifstep.mT1 = -1; // Sets obligatory flag. simplifstep.obligatory = obligatory; // Clears faces list. simplifstep.mModfaces.clear(); // mModfaces y mT0, mT1 of simplifstep stores // the triangles id's -> geomesh has not triangles id's. for (i = 0; i < changed.length(); i++) { simplif::Face *auxface = changed(i); if (auxface->isValid()) { // Modified triangles. simplifstep.mModfaces.push_back(auxface->validID()); } else { // Removed triangles. if (_numDelTris == 1) { simplifstep.mT0 = auxface->validID(); simplifstep.mT1 = auxface->validID(); } else { if(del_index == 0) { simplifstep.mT0 = auxface->validID(); del_index++; } else { simplifstep.mT1 = auxface->validID(); } } } } // Simplification sequence that make reference to the // simplification method sequence. //decim_data.push_back(simplifstep); // Adds new simplification step. msimpseq->mSteps.push_back(simplifstep); #ifdef SUPPORT_VCOLOR // If the vertices are colored, color the new vertex // using the average of the old colors. v0->props->color += v1->props->color; v0->props->color /= 2; #endif // Remove the pair that we just contracted. delete_pair(auxpair); // Recalculate pairs associated with v0. for (i = 0; i < v0_info->pairs.length(); i++) { simplif::pair_info *p = v0_info->pairs(i); compute_pair_info(p); } // Process pairs associated with now dead vertex. // Collect condemned pairs for execution. static simplif::pair_buffer condemned(6); condemned.reset(); // Recalculate pairs associated with v1. for (i = 0; i < v1_info->pairs.length(); i++) { simplif::pair_info *p = v1_info->pairs(i); simplif::Vertex *u; if ( p->v0 == v1 ) { u = p->v1; } else { if ( p->v1 == v1) { u = p->v0; } else { std::cerr << "YOW! This is a bogus pair." << endl; } } if ( !check_for_pair(u, v0) ) { p->v0 = v0; p->v1 = u; v0_info->pairs.add(p); compute_pair_info(p); } else { condemned.add(p); } } for (i = 0; i < condemned.length(); i++) { // Do you have any last requests? delete_pair(condemned(i)); } // Safety precaution. v1_info->pairs.reset(); } //------------------------------------------------------------------------- //------------------------------------------------------------------------- bool SimplificationMethod::decimate_quadric(simplif::Vertex *v, simplif::Mat4& Q) { if( vinfo.length() > 0 ) { Q = vinfo(v->uniqID)->Q; return true; } else { return false; } } //------------------------------------------------------------------------- // Extract a pair from the heap, concract it and remove it from the heap. //------------------------------------------------------------------------- void SimplificationMethod::decimate_contract(simplif::Model& m) { simplif::heap_node *top; simplif::pair_info *pair; simplif::Vertex *v0; simplif::Vertex *v1; simplif::Vec3 candidate; _float3_ f0; _float3_ f1; for (;;) { top = heap->extract(); if (!top) { return; } pair = (simplif::pair_info *)top->obj; // Remove all the vertices of the removed edges. bool sharededge = false; for (int i = 0; i < pair->v0->edgeUses().length(); i++) { simplif::Edge *econ = pair->v0->edgeUses()(i); if (pair->v1->vID == econ->org()->vID || pair->v1->vID == econ->dest()->vID) { sharededge = true; break; } } // Coordinates of the pair. f0 = _float3_((*pair->v0)[X],(*pair->v0)[Y],(*pair->v0)[Z]); f1 = _float3_((*pair->v1)[X],(*pair->v1)[Y],(*pair->v1)[Z]); if (pair->isValid() && sharededge && (vertexMultimap.find(f0) != vertexMultimap.end()) && (vertexMultimap.find(f1) != vertexMultimap.end()) && ((*pair->v0) != (*pair->v1))) { break; } // Debug. cout << "Deleting pair (" << pair->v0->vID << "--" << pair->v1->vID << ")" << endl; // Deletes repetitions of pair in heap. delete_pair(pair); } // Copy pair. v0 = new Vertex( (*pair->v0)[X], (*pair->v0)[Y], (*pair->v0)[Z]); v0->vID = pair->v0->vID; v1 = new Vertex( (*pair->v1)[X], (*pair->v1)[Y], (*pair->v1)[Z]); v1->vID = pair->v1->vID; candidate = pair->candidate; // Debug. cout << "Contracting... " << endl; // Contract main pair. do_contract(m, pair, 0); // Attempt to maintain valid vertex information. M0.validVertCount--; // Find twin vertices to the contracted one and contract them. removeTwinVertices(m,v0,v1,candidate); // Free Memory. delete v0; delete v1; } //------------------------------------------------------------------------- // Find twin vertices to the contracted one and contract them. //------------------------------------------------------------------------- void SimplificationMethod::removeTwinVertices(simplif::Model &m, simplif::Vertex *v0, simplif::Vertex *v1, simplif::Vec3 candidate) { bool twin_found; simplif::Edge *edge; simplif::pair_info *pair; simplif::Vertex *vert; simplif::Vertex *lonely_vert; simplif::Vertex *new_vert; vertex_map_str lb; vertex_map_str ub; vertex_map_str it; _float3_ f0; _float3_ f1; simplif::Edge *econ; simplif::vert_info new_vert_info; Geometry::GeoVertex vertex_added; simplif::Vertex *take_bone_from_vert; float x,y,z; // Gets the vertex that is not the candidate. if ((*v1) == candidate) { vert = v0; v0 = v1; v1 = vert; } take_bone_from_vert = v0; f0 = _float3_((*v0)[X],(*v0)[Y],(*v0)[Z]); f1 = _float3_((*v1)[X],(*v1)[Y],(*v1)[Z]); while ((it = vertexMultimap.find(f1)) != vertexMultimap.end()) { twin_found = false; lonely_vert = m.vertex((*it).second); // Debug. if ((*it).second == 10988) { cout << "Lonely: " << lonely_vert->vID << endl; } for (int i = 0; i < lonely_vert->edgeUses().length(); i++) { econ = lonely_vert->edgeUses()(i); if (((*econ->org()) == (*v0)) || ((*econ->dest()) == (*v0))) { lb = vertexMultimap.lower_bound(f0); ub = vertexMultimap.upper_bound(f0); // For each vertex. while (lb != ub) { // If removed vertex is found. if (((*lb).second == econ->org()->vID) || ((*lb).second == econ->dest()->vID)) { twin_found = true; // Break while. lb = ub; } else { // Next iteration. lb++; } } break; } } // If a twin edge has been found. if (twin_found) { // Debug. cout << "Twin Contracted..." << endl; // Extract twin edge from heap. pair = new_pair(econ->org(),econ->dest()); // Copy candidate. pair->candidate = candidate; pair->notInHeap(); // Contract twin pair. do_contract(m, pair, 1); M0.validVertCount--; } else { // Debug. cout << "Contracting new pair..." << endl; new_vert = m.newVertex(candidate[X],candidate[Y],candidate[Z]); // Add new vert to multimap. x = (*new_vert)[X]; y = (*new_vert)[Y]; z = (*new_vert)[Z]; // Adds new vertex to multimap. vertexMultimap.insert(vertex_pair(_float3_(x,y,z),new_vert->vID)); // Creates new edge. edge = m.newEdge(new_vert,lonely_vert); // We assume here there are the same number of vertices // and texture coordinates and normals. // Assign a texture coordinate for the vertex. simplif::Vec2 newtexcoord = m.texcoord(lonely_vert->vID); m.in_TexCoord(newtexcoord); // Assign a normal coordinate for the vbertex. simplif::Vec3 newnormal = m.normal(lonely_vert->vID); m.in_Normal(newnormal); // Adds new vertex information to simplification sequence. vertex_added.id = new_vert->vID; vertex_added.bonefrom = take_bone_from_vert->vID; vertex_added.position = Vector3(candidate[X], candidate[Y], candidate[Z]); simplif::Vec2 tc = m.texcoord(new_vert->vID); vertex_added.texcoord = Vector2(tc[X],tc[Y]); simplif::Vec3 vn = m.normal(new_vert->vID); vertex_added.normal = Vector3(vn[X],vn[Y],vn[Z]); msimpseq->mNewVertices.push_back(vertex_added); // Debug. vert_info *new_vert_info; new_vert_info = new vert_info(); vinfo.add(new_vert_info); //------------------------------ pair = new_pair(new_vert,lonely_vert); pair->candidate = candidate; pair->notInHeap(); // Debug. cout << "new: " << new_vert->vID << "(" << (*new_vert)[X] << "," << (*new_vert)[Y] << "," << (*new_vert)[Z] << ") lonely: " << lonely_vert->vID << "(" << (*lonely_vert)[X] << "," << (*lonely_vert)[Y] << "," << (*lonely_vert)[Z] << ")" << endl; // Contract new pair. do_contract(m, pair, 1); M0.validVertCount--; } } } //------------------------------------------------------------------------- //------------------------------------------------------------------------- simplif::real SimplificationMethod::decimate_error(simplif::Vertex *v) { simplif::vert_info *info = vertex_info(v); simplif::real err = simplif::quadrix_evaluate_vertex(*v, info->Q); if ( simplif::will_weight_by_area ) { err /= info->norm; } return err; } //------------------------------------------------------------------------- // Extract the minimum cost of the the valid nodes (not simplified) //------------------------------------------------------------------------- simplif::real SimplificationMethod::decimate_min_error() { simplif::heap_node *top; simplif::pair_info *pair; for(;;) { top = heap->top(); if(!top) { return -1.0; } pair = (simplif::pair_info *)top->obj; if(pair->isValid()) { break; } top = heap->extract(); delete_pair(pair); } return pair->cost; } //------------------------------------------------------------------------- // Returns the maximum error by vertex //------------------------------------------------------------------------- simplif::real SimplificationMethod::decimate_max_error(simplif::Model& m) { simplif::real max_err = 0; for(int i=0; iisValid()) { max_err = MAX(max_err, decimate_error(m.vertex(i))); } return max_err; } //------------------------------------------------------------------------- // Initializations //------------------------------------------------------------------------- void SimplificationMethod::decimate_init( simplif::Model &m, simplif::real limit) { int i,j; // Reserve memory for vert_info array. for (i = 0; i < m.vertCount(); i++) { vert_info *new_vert_info; new_vert_info = new vert_info(); vinfo.add(new_vert_info); } if (simplif::will_use_vertex_constraint) { // For each vertex, calculate contraints. for (i = 0; i < m.vertCount(); i++) { simplif::Vertex *v = m.vertex(i); if (v->isValid()) { vertex_info(v)->Q = simplif::quadrix_vertex_constraint(*v); } } } // For each face, recalculate constraints. for (i = 0; i < m.faceCount(); i++) { if (m.face(i)->isValid()) { if (simplif::will_use_plane_constraint) { simplif::Mat4 Q = simplif::quadrix_plane_constraint(*m.face(i)); simplif::real norm = 0.0; if (simplif::will_weight_by_area) { norm = m.face(i)->area(); Q *= norm; } for (j = 0; j < 3; j++) { vertex_info(m.face(i)->vertex(j))->Q += Q; vertex_info(m.face(i)->vertex(j))->norm += norm; } } } } if (simplif::will_constrain_boundaries) { // For each edge, recalculate constraints. for (i = 0; i < m.edgeCount(); i++) { if (m.edge(i)->isValid() && simplif::check_for_discontinuity(m.edge(i))) { simplif::Mat4 B = simplif::quadrix_discontinuity_constraint(m.edge(i)); simplif::real norm = 0.0; if (simplif::will_weight_by_area) { norm = simplif::norm2(*m.edge(i)->org() - *m.edge(i)->dest()); B *= norm; } B *= simplif::boundary_constraint_weight; vertex_info(m.edge(i)->org())->Q += B; vertex_info(m.edge(i)->org())->norm += norm; vertex_info(m.edge(i)->dest())->Q += B; vertex_info(m.edge(i)->dest())->norm += norm; } } } // Create heap. heap = new simplif::Heap(m.validEdgeCount); int pair_count = 0; // For each edge, add pairs to heap. for (i = 0; i < m.edgeCount(); i++) { if (m.edge(i)->isValid()) { simplif::pair_info *pair = new_pair(m.edge(i)->org(), m.edge(i)->dest()); //pointers_to_remove.push_back(pair); compute_pair_info(pair); pair_count++; } } if (limit < 0) { limit = m.bounds.radius * 0.05; } proximity_limit = limit * limit; if (proximity_limit > 0) { simplif::ProxGrid grid(m.bounds.min, m.bounds.max, limit); // Add points to grid. for (i = 0; i < m.vertCount(); i++) { grid.addPoint(m.vertex(i)); } simplif::buffer nearby(32); // For each vertex. for (i = 0; i < m.vertCount(); i++) { nearby.reset(); grid.proximalPoints(m.vertex(i), nearby); for (j = 0; j < nearby.length(); j++) { simplif::Vertex *v1 = m.vertex(i); simplif::Vertex *v2 = (simplif::Vertex *)nearby(j); if (v1->isValid() && v2->isValid()) { #ifdef SAFETY assert(pair_is_valid(v1,v2)); #endif if (!check_for_pair(v1,v2)) { simplif::pair_info *pair = new_pair(v1,v2); compute_pair_info(pair); pair_count++; } } } } } } //------------------------------------------------------------------------- // Initilizations //------------------------------------------------------------------------- void SimplificationMethod::simplifmethod_init(void) { // Change mesh structure. generateSimplifModel(); M0.bounds.complete(); initialVertCount = M0.vertCount(); initialEdgeCount = M0.edgeCount(); initialFaceCount = M0.faceCount(); // Get rid of degenerate faces. for (int i = 0; i < M0.faceCount(); i++) { if (!M0.face(i)->plane().isValid()) { M0.killFace(M0.face(i)); } } M0.removeDegeneracy(M0.allFaces()); // Get rid of unused vertices. for (int i = 0; i < M0.vertCount(); i++) { if (M0.vertex(i)->edgeUses().length() == 0) { M0.vertex(i)->kill(); } } } //------------------------------------------------------------------------- // Do the contractions till the required LOD (percentage option) //------------------------------------------------------------------------- void SimplificationMethod::simplifmethod_run(int finalfaces,TIPOFUNC upb) { decimate_init(M0, simplif::pair_selection_tolerance); unsigned int contador = 0; float percent; // simplification percentage. percent = (float)(2.0 * 100.0) / (M0.validFaceCount - finalfaces); // Update progress bar. if (upb) { upb(0.0); } /* for ( std::vector::iterator it = decim_data.begin(); it != decim_data.end(); it++) { it->mModfaces.clear(); } decim_data.clear(); */ // Debug. cout << "M0.validFaceCount: " << M0.validFaceCount << endl; cout << "finalfaces: " << finalfaces << endl; while ( M0.validFaceCount > finalfaces/*simplif::face_target*/ && M0.validFaceCount > 1 && decimate_min_error() < simplif::error_tolerance ) { decimate_contract(M0); // Update progress bar. if (upb) { upb(percent); } } // Update progress bar. if (upb) { upb(100.0); } } //------------------------------------------------------------------------- // Do the contractions till the required LOD (number of vertices option) //------------------------------------------------------------------------- void SimplificationMethod::simplifmethod_runv(int numvertices,TIPOFUNC upb) { decimate_init(M0, simplif::pair_selection_tolerance); unsigned int contador = 0; int previousValidVertCount; float percent; // Simplification percentage. previousValidVertCount = 0; percent = (float)(2.0 * 100.0) / (float)((M0.validFaceCount - numvertices / 3.0)); // Update progress bar. if (upb) { upb(0.0); } /* for ( std::vector::iterator it = decim_data.begin(); it != decim_data.end(); it++) { it->mModfaces.clear(); } decim_data.clear(); */ // Debug. cout << "M0.validVertCount: " << M0.validVertCount << endl; cout << "numvertices: " << numvertices << endl; while( M0.validVertCount > numvertices /*simplif::face_target*/ && decimate_min_error() < simplif::error_tolerance && previousValidVertCount != M0.validVertCount) { previousValidVertCount = M0.validVertCount; decimate_contract(M0); // Update progress bar. if (upb) { upb(percent); } } // Update progress bar. if (upb) { upb(100.0); } } //------------------------------------------------------------------------- // Generate simplification model. //------------------------------------------------------------------------- void SimplificationMethod::generateSimplifModel(void) { int face_index = 0; int vertID; float x,y,z; // For each submesh. bool added_vertices = false; for (size_t i = 0; i < mInitialMesh->mSubMeshCount; i++) { // If is not a tree leaves submesh. if (i != indexMeshLeaves) { // For all the vertices of each submesh. for ( size_t j = 0; j < mInitialMesh->mSubMesh[i].mVertexBuffer->mVertexCount; j++) { x = mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].x; y = mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].y; z = mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].z; // If the vertex is not in vertices_map, then is added. vertID = M0.in_Vertex(simplif::Vec3( mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].x, mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].y, mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].z)); M0.in_Normal(simplif::Vec3( mInitialMesh->mSubMesh[i].mVertexBuffer->mNormal[j].x, mInitialMesh->mSubMesh[i].mVertexBuffer->mNormal[j].y, mInitialMesh->mSubMesh[i].mVertexBuffer->mNormal[j].z)); M0.in_TexCoord(simplif::Vec2( mInitialMesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].x, mInitialMesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].y)); added_vertices = true; // Add vertex to multimap. vertexMultimap.insert(vertex_pair(_float3_(x,y,z),vertID)); } } // If is shared vertex buffer object. if (mInitialMesh->mSubMesh[i].mSharedVertexBuffer && added_vertices) { printf("Shared break"); break; } } // For each submesh. for (size_t i = 0; i < mInitialMesh->mSubMeshCount; i++) { if (i != indexMeshLeaves) { for ( Geometry::Index j = 0; j < mInitialMesh->mSubMesh[i].mIndexCount; j += 3) { // +1 is required because the first index in the // simplification method is 1 // Index of the vertex in vertices_map. Geometry::Index index0 = mInitialMesh->mSubMesh[i].mIndex[j]; Geometry::Index index1 = mInitialMesh->mSubMesh[i].mIndex[j + 1]; Geometry::Index index2 = mInitialMesh->mSubMesh[i].mIndex[j + 2]; // Create a triangle with its indices in vertices_map. face_index = M0.miin_Face( index0, index1, index2); // igeo allows to identify the submesh that contains the triangle. M0.face(face_index)->igeo = (int)i; } } } number_of_triangles = face_index; } //------------------------------------------------------------------------- // simplifmethod_init is executed to do some initalizations // simplifmethod_run is executed to do the decimation // Then, the simpified model is created and the decimation // information is returned. //------------------------------------------------------------------------- MeshSimplificationSequence *SimplificationMethod::Decimate( float lod, int simpliftype, TIPOFUNC upb) { bool shared_vertex; unsigned int vertex_count; std::map::iterator findit; // Initialize vertex count. vertex_count = 0; // Initialize shared vertex buffer flag. shared_vertex = false; // Determines if the mesh have shared vertex buffer. for (int i = 0; i < mInitialMesh->mSubMeshCount; i++) { if (mInitialMesh->mSubMesh[i].mSharedVertexBuffer) { shared_vertex = true; break; } } simplifmethod_init(); if (simpliftype == 0) { // Percentage option. simplifmethod_run((int)(number_of_triangles*lod),upb); } else { // Number of vertices option. simplifmethod_runv((int)lod,upb); } MAPAINDIND *unique_verts_inds_by_geo = new MAPAINDIND[mInitialMesh->mSubMeshCount]; MAPAINDIND shared_vertex_map; REPINDLIST *ver_inds_rep_by_geo = new REPINDLIST[mInitialMesh->mSubMeshCount]; // Index counter by submesh. int *inextvert = new int[mInitialMesh->mSubMeshCount]; for (unsigned int i = 0; i < mInitialMesh->mSubMeshCount; i++) { inextvert[i] = 0; } // Construct the model. std::cout << "M0.faceCount(): " << M0.faceCount() << std::endl; // For each face. for (int i = 0; i < M0.faceCount(); i++) { if (M0.face(i)->isValid()) { simplif::Face *auxface = M0.face(i); // Determine to which submesh pertains the triangle. int igeo = auxface->igeo; // For each index of the face. for (size_t j = 0; j < 3; j++) { if (shared_vertex) { // Insert to each submesh its triangles. findit = shared_vertex_map.find(auxface->vertex(j)->vID); if (findit == shared_vertex_map.end()) { // If it is not added... add and map it. shared_vertex_map[auxface->vertex(j)->vID] = vertex_count; vertex_count++; } } else { // Insert to each submesh its triangles. findit = unique_verts_inds_by_geo[igeo]. find(auxface->vertex(j)->vID); if (findit == unique_verts_inds_by_geo[igeo].end()) { // If it is not added... add and map it. unique_verts_inds_by_geo[igeo][auxface->vertex(j)->vID] = inextvert[igeo]; inextvert[igeo]++; } } // Total number of indices by submesh. ver_inds_rep_by_geo[igeo].push_back(auxface->vertex(j)->vID); } } } // Output simplified mesh. mGeoMesh = new Mesh(); mGeoMesh->mVertexBuffer = new VertexBuffer(); mGeoMesh->mSubMeshCount = mInitialMesh->mSubMeshCount; // Memory allocation for the submeshes. mGeoMesh->mSubMesh = new SubMesh[mInitialMesh->mSubMeshCount]; // Fill up bounding box settings. mGeoMesh->mMeshBounds.maxX = mInitialMesh->mMeshBounds.maxX; mGeoMesh->mMeshBounds.maxY = mInitialMesh->mMeshBounds.maxY; mGeoMesh->mMeshBounds.maxZ = mInitialMesh->mMeshBounds.maxZ; mGeoMesh->mMeshBounds.minX = mInitialMesh->mMeshBounds.minX; mGeoMesh->mMeshBounds.minY = mInitialMesh->mMeshBounds.minY; mGeoMesh->mMeshBounds.minZ = mInitialMesh->mMeshBounds.minZ; mGeoMesh->mMeshBounds.radius = mInitialMesh->mMeshBounds.radius; mGeoMesh->mMeshBounds.scaleFactor = mInitialMesh->mMeshBounds.scaleFactor; // Copy skeleton name. if (mInitialMesh->hasSkeleton) { mGeoMesh->hasSkeleton = true; strcpy(mGeoMesh->mSkeletonName,mInitialMesh->mSkeletonName); } // If the mesh has shared vertex. if (shared_vertex) { fillUpSharedVertices(shared_vertex_map,ver_inds_rep_by_geo); } else { fillUpVertices(unique_verts_inds_by_geo,ver_inds_rep_by_geo); } //------------------------// // Bones reassignment. // //------------------------// VertexBoneAssignment bone; bool vertex_found; MAPAINDIND::iterator it; addNewBoneAssignments(); // For each bone assignment. for (unsigned int i = 0; i < mInitialMesh->mBones.size(); i++) { bone.vertexIndex = mInitialMesh->mBones[i].vertexIndex; bone.boneIndex = mInitialMesh->mBones[i].boneIndex; bone.weight = mInitialMesh->mBones[i].weight; vertex_found = false; // If the vertex is found in the simplification model. if ((it = shared_vertex_map.find(bone.vertexIndex)) != shared_vertex_map.end()) { bone.vertexIndex = (*it).second; mGeoMesh->mBones.push_back(bone); vertex_found = true; } } //------------------------------------------------------------// delete[] unique_verts_inds_by_geo; delete[] ver_inds_rep_by_geo; delete[] inextvert; // Store the simplification steps in MeshSimplificationSequence. int acum = 0; for (size_t i = 0; i < mInitialMesh->mSubMeshCount; i++) { if (mInitialMesh->mSubMesh[i].mSharedVertexBuffer) { first_index_submesh[i] = 0; } else { first_index_submesh[i] = acum; } acum += (int)mInitialMesh->mSubMesh[i].mVertexBuffer->mVertexCount; } vector v0; vector v1; vector submesh0; vector submesh1; return msimpseq; } //------------------------------------------------------------------------- // Add bone assignments for new bones. //------------------------------------------------------------------------- void SimplificationMethod::addNewBoneAssignments() { size_t vertex_id; size_t bones_count; VertexBoneAssignment bone; vector::iterator it; // Copy new vertices. for (unsigned int i = 0; i < msimpseq->mNewVertices.size(); i++) { vertex_id = msimpseq->mNewVertices[i].id; // Initialize number of bones. bones_count = mInitialMesh->mBones.size(); // check if my twin-vertex-bone has a bone assignment // we check only the GeoMesh bones because the lodstrips // only works for sharedvertex bones. for (int j = 0; j < bones_count; j++) { it = mInitialMesh->mBones.begin() + j; if (it->vertexIndex == msimpseq->mNewVertices[i].bonefrom) { bone.vertexIndex = vertex_id; bone.boneIndex = it->boneIndex; bone.weight = it->weight; mInitialMesh->mBones.push_back(bone); bones_count++; } } } } //------------------------------------------------------------------------- // Fill up vertices. //------------------------------------------------------------------------- void SimplificationMethod::fillUpVertices( MAPAINDIND *unique_verts_inds_by_geo, REPINDLIST *ver_inds_rep_by_geo) { bool copiedShared = false; // For each submesh. for (size_t i = 0; i < mInitialMesh->mSubMeshCount; i++) { mGeoMesh->mSubMesh[i].mStripCount = 0; mGeoMesh->mSubMesh[i].mStrip = NULL; mGeoMesh-> mSubMesh[i].mSharedVertexBuffer = false; strcpy( mGeoMesh->mSubMesh[i].mMaterialName, mInitialMesh->mSubMesh[i].mMaterialName); // Copy submesh bones. if (!mInitialMesh->mSubMesh[i].mBones.empty()) { for ( unsigned int j = 0; j < mInitialMesh->mSubMesh[i].mBones.size(); j++) { mGeoMesh->mSubMesh[i].mBones.push_back(mInitialMesh-> mSubMesh[i].mBones[j]); } } if (i != indexMeshLeaves) { // Indices vectors. mGeoMesh->mSubMesh[i].mIndexCount = ver_inds_rep_by_geo[i].size(); mGeoMesh->mSubMesh[i].mIndex = new Geometry::Index[mGeoMesh-> mSubMesh[i].mIndexCount]; // Store the indices. for (unsigned int j = 0; j < mGeoMesh->mSubMesh[i].mIndexCount; j++) { // Obtain the indices that point at VertexBuffer. mGeoMesh->mSubMesh[i].mIndex[j] = unique_verts_inds_by_geo[i][ver_inds_rep_by_geo[i][j]]; } // Copy the vertices. if (mGeoMesh->mSubMesh[i].mSharedVertexBuffer) { // Shared vertices. if (!copiedShared) { mGeoMesh->mVertexBuffer = new VertexBuffer(); copiedShared = true; } mGeoMesh->mSubMesh[i].mVertexBuffer = mGeoMesh->mVertexBuffer; } else { // There's no shared vertices. mGeoMesh->mSubMesh[i].mVertexBuffer = new VertexBuffer(); } mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount = unique_verts_inds_by_geo[i].size(); mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexInfo = mInitialMesh->mSubMesh[i].mVertexBuffer->mVertexInfo; // Allocate memory for position, normal and texutre coordinates. mGeoMesh->mSubMesh[i].mVertexBuffer->mPosition = new Vector3[mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount]; mGeoMesh->mSubMesh[i].mVertexBuffer->mNormal = new Vector3[mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount]; mGeoMesh->mSubMesh[i].mVertexBuffer->mTexCoords = new Vector2[mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount]; for (MAPAINDIND::iterator mapit = unique_verts_inds_by_geo[i].begin(); mapit != unique_verts_inds_by_geo[i].end(); mapit++) { // Key and value. int isrc = mapit->first; int idst = mapit->second; // Vertex coordinate. // Construction of the submeshes. Vector3 v3( (Real)M0.vertex(isrc)->operator [](0), (Real)M0.vertex(isrc)->operator [](1), (Real)M0.vertex(isrc)->operator [](2)); mGeoMesh->mSubMesh[i].mVertexBuffer->mPosition[idst] = v3; // Normal coordinates. Vector3 v3n( (Real)M0.normal(isrc)(0), (Real)M0.normal(isrc)(1), (Real)M0.normal(isrc)(2)); mGeoMesh->mSubMesh[i].mVertexBuffer->mNormal[idst] = v3n; // Texture coordinates. Vector2 v2( (Real)M0.texcoord(isrc)(0), (Real)M0.texcoord(isrc)(1)); mGeoMesh->mSubMesh[i].mVertexBuffer->mTexCoords[idst] = v2; } } // Leaves mesh. else { mGeoMesh->mSubMesh[i].mIndexCount = mInitialMesh->mSubMesh[i].mIndexCount; mGeoMesh->mSubMesh[i].mIndex = new Geometry::Index[mGeoMesh->mSubMesh[i].mIndexCount]; // Copy the leaves submesh indexes. for ( unsigned int j = 0; j < mGeoMesh->mSubMesh[i].mIndexCount; j++) { mGeoMesh->mSubMesh[i].mIndex[j] = mInitialMesh->mSubMesh[i].mIndex[j]; } // Copy the leaves submesh vertices. mGeoMesh->mSubMesh[i].mVertexBuffer = new VertexBuffer(); mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount = mInitialMesh->mSubMesh[i].mVertexBuffer->mVertexCount; mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexInfo = mInitialMesh->mSubMesh[i].mVertexBuffer->mVertexInfo; // Allocate memory for position, normal and texture coordinates. mGeoMesh->mSubMesh[i].mVertexBuffer->mPosition = new Vector3[mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount]; mGeoMesh->mSubMesh[i].mVertexBuffer->mNormal = new Vector3[mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount]; mGeoMesh->mSubMesh[i].mVertexBuffer->mTexCoords = new Vector2[mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount]; for ( unsigned int j = 0; j < mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount; j++) { // Position. mGeoMesh->mSubMesh[i].mVertexBuffer->mPosition[j].x = mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].x; mGeoMesh->mSubMesh[i].mVertexBuffer->mPosition[j].y = mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].y; mGeoMesh->mSubMesh[i].mVertexBuffer->mPosition[j].z = mInitialMesh->mSubMesh[i].mVertexBuffer->mPosition[j].z; // Normals. mGeoMesh->mSubMesh[i].mVertexBuffer->mNormal[j].x = mInitialMesh->mSubMesh[i].mVertexBuffer->mNormal[j].x; mGeoMesh->mSubMesh[i].mVertexBuffer->mNormal[j].y = mInitialMesh->mSubMesh[i].mVertexBuffer->mNormal[j].y; mGeoMesh->mSubMesh[i].mVertexBuffer->mNormal[j].z = mInitialMesh->mSubMesh[i].mVertexBuffer->mNormal[j].z; // Textures. mGeoMesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].x = mInitialMesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].x; mGeoMesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].y = mInitialMesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].y; } } } } //------------------------------------------------------------------------- // Fill up shared vertices. //------------------------------------------------------------------------- void SimplificationMethod::fillUpSharedVertices( MAPAINDIND &shared_vertex_map, REPINDLIST *ver_inds_rep_by_geo) { mGeoMesh->mVertexBuffer = new VertexBuffer(); // For each submesh. for (size_t i = 0; i < mInitialMesh->mSubMeshCount; i++) { mGeoMesh-> mSubMesh[i].mSharedVertexBuffer = mInitialMesh-> mSubMesh[i].mSharedVertexBuffer; // Reassign submesh vertex buffers. mGeoMesh->mSubMesh[i].mVertexBuffer = mGeoMesh->mVertexBuffer; mGeoMesh->mSubMesh[i].mStripCount = 0; mGeoMesh->mSubMesh[i].mStrip = NULL; strcpy( mGeoMesh->mSubMesh[i].mMaterialName, mInitialMesh->mSubMesh[i].mMaterialName); // Indices vectors. mGeoMesh->mSubMesh[i].mIndexCount = ver_inds_rep_by_geo[i].size(); mGeoMesh->mSubMesh[i].mIndex = new Geometry::Index[mGeoMesh-> mSubMesh[i].mIndexCount]; // Store the indices. for (unsigned int j = 0; j < mGeoMesh->mSubMesh[i].mIndexCount; j++) { // Obtain the indices that point at VertexBuffer. mGeoMesh->mSubMesh[i].mIndex[j] = shared_vertex_map[ver_inds_rep_by_geo[i][j]]; } } mGeoMesh->mVertexBuffer->mVertexCount = shared_vertex_map.size(); mGeoMesh->mVertexBuffer->mVertexInfo = mInitialMesh->mVertexBuffer->mVertexInfo; // Allocate memory for position, normal and texutre coordinates. mGeoMesh->mVertexBuffer->mPosition = new Vector3[mGeoMesh->mVertexBuffer->mVertexCount]; mGeoMesh->mVertexBuffer->mNormal = new Vector3[mGeoMesh->mVertexBuffer->mVertexCount]; mGeoMesh->mVertexBuffer->mTexCoords = new Vector2[mGeoMesh->mVertexBuffer->mVertexCount]; for (MAPAINDIND::iterator mapit = shared_vertex_map.begin(); mapit != shared_vertex_map.end(); mapit++) { // Key and value. int isrc = mapit->first; int idst = mapit->second; // Vertex coordinate. // Construction of the submeshes. Vector3 v3( (Real)M0.vertex(isrc)->operator [](0), (Real)M0.vertex(isrc)->operator [](1), (Real)M0.vertex(isrc)->operator [](2)); mGeoMesh->mVertexBuffer->mPosition[idst] = v3; // Normal coordinates. Vector3 v3n((Real)M0.normal(isrc)(0), (Real)M0.normal(isrc)(1), (Real)M0.normal(isrc)(2)); mGeoMesh->mVertexBuffer->mNormal[idst] = v3n; // Texture coordinates. Vector2 v2( (Real)M0.texcoord(isrc)(0), (Real)M0.texcoord(isrc)(1)); mGeoMesh->mVertexBuffer->mTexCoords[idst] = v2; } } //------------------------------------------------------------------------- // Set submesh leaves. //------------------------------------------------------------------------- void SimplificationMethod::setMeshLeaves(int meshLeaves) { indexMeshLeaves = meshLeaves; } // Gets mesh simplified. Mesh * SimplificationMethod::GetMesh() { return mGeoMesh; }