|
Blender
V2.59
|
00001 /* 00002 * $Id: LOD_NdQSDecimator.cpp 35147 2011-02-25 10:47:28Z jesterking $ 00003 * ***** BEGIN GPL LICENSE BLOCK ***** 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software Foundation, 00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00020 * All rights reserved. 00021 * 00022 * The Original Code is: all of this file. 00023 * 00024 * Contributor(s): none yet. 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include "LOD_NdQSDecimator.h" 00035 00036 #include "LOD_ExternBufferEditor.h" 00037 #include "LOD_ExternNormalEditor.h" 00038 #include "LOD_ExternVColorEditor.h" 00039 #include "TNT/lu.h" 00040 00041 #include <iostream> 00042 00043 using namespace std; 00044 00045 LOD_NdQSDecimator * 00046 LOD_NdQSDecimator:: 00047 New( 00048 LOD_ManMesh2 &mesh, 00049 LOD_ExternNormalEditor &face_editor, 00050 LOD_ExternVColorEditor &color_editor, 00051 LOD_ExternBufferEditor &extern_editor 00052 ){ 00053 00054 NanPtr<LOD_NdQSDecimator> output 00055 = new LOD_NdQSDecimator(mesh,face_editor,color_editor,extern_editor); 00056 00057 NanPtr<LOD_EdgeCollapser > collapser(LOD_EdgeCollapser::New()); 00058 NanPtr<LOD_NdQuadricEditor> q_editor(LOD_NdQuadricEditor::New(mesh)); 00059 00060 if ( 00061 output == NULL || 00062 collapser == NULL || 00063 q_editor == NULL 00064 ) { 00065 return NULL; 00066 } 00067 output->m_collapser = collapser.Release(); 00068 output->m_quadric_editor = q_editor.Release(); 00069 return output.Release(); 00070 } 00071 00072 00073 00074 bool 00075 LOD_NdQSDecimator:: 00076 Arm( 00077 ){ 00078 MT_assert(!m_is_armed); 00079 bool heap_result = BuildHeap(); 00080 if (!heap_result) { 00081 return false; 00082 } 00083 m_is_armed = true; 00084 return true; 00085 } 00086 00087 bool 00088 LOD_NdQSDecimator:: 00089 Step( 00090 ){ 00091 return CollapseEdge(); 00092 } 00093 00094 00095 LOD_NdQSDecimator:: 00096 LOD_NdQSDecimator( 00097 LOD_ManMesh2 &mesh, 00098 LOD_ExternNormalEditor &face_editor, 00099 LOD_ExternVColorEditor &color_editor, 00100 LOD_ExternBufferEditor &extern_editor 00101 ) : 00102 m_mesh(mesh), 00103 m_face_editor(face_editor), 00104 m_color_editor(color_editor), 00105 m_extern_editor(extern_editor), 00106 m_is_armed (false) 00107 { 00108 m_deg_edges.reserve(32); 00109 m_deg_faces.reserve(32); 00110 m_deg_vertices.reserve(32); 00111 m_update_faces.reserve(32); 00112 m_new_edges.reserve(32); 00113 m_update_vertices.reserve(32); 00114 }; 00115 00116 bool 00117 LOD_NdQSDecimator:: 00118 CollapseEdge( 00119 ){ 00120 00121 // find an edge to collapse 00122 00123 // FIXME force an edge collapse 00124 // or return false 00125 00126 vector<LOD_Edge> & edges = m_mesh.EdgeSet(); 00127 vector<LOD_Vertex> & verts = m_mesh.VertexSet(); 00128 vector<LOD_NdQuadric> & quadrics = m_quadric_editor->Quadrics(); 00129 int size = edges.size(); 00130 00131 if (size == 0) return false; 00132 00133 const int heap_top = m_heap->Top(); 00134 00135 if (heap_top == -1 || edges[heap_top].HeapKey() <= -MT_INFINITY) { 00136 return false; 00137 } 00138 00139 // compute the target position 00140 00141 TNT::Vector<MT_Scalar> new_vector(6,MT_Scalar(0)); 00142 00143 m_quadric_editor->TargetVertex(edges[heap_top],new_vector,m_color_editor); 00144 00145 00146 MT_Vector3 new_vertex( 00147 new_vector[0], 00148 new_vector[1], 00149 new_vector[2] 00150 ); 00151 for (int i = 3; i < 6;i++) { 00152 if (new_vector[i] > MT_Scalar(1)) { 00153 new_vector[i] = MT_Scalar(1); 00154 } else 00155 if (new_vector[i] < MT_Scalar(0)) { 00156 new_vector[i] = MT_Scalar(0); 00157 } 00158 } 00159 MT_Vector3 new_color( 00160 new_vector[3], 00161 new_vector[4], 00162 new_vector[5] 00163 ); 00164 00165 // bounds check? 00166 00167 00168 LOD_NdQuadric & q0 = quadrics[edges[heap_top].m_verts[0]]; 00169 LOD_NdQuadric & q1 = quadrics[edges[heap_top].m_verts[1]]; 00170 00171 const LOD_VertexInd v0ind = edges[heap_top].m_verts[0]; 00172 const LOD_VertexInd v1ind = edges[heap_top].m_verts[1]; 00173 00174 LOD_Vertex &v0 = verts[v0ind]; 00175 LOD_Vertex &v1 = verts[v1ind]; 00176 00177 LOD_NdQuadric sum = q0; 00178 sum += q1; 00179 00180 00181 if (m_collapser->CollapseEdge( 00182 heap_top, 00183 m_mesh, 00184 m_deg_edges, 00185 m_deg_faces, 00186 m_deg_vertices, 00187 m_new_edges, 00188 m_update_faces, 00189 m_update_vertices 00190 )) { 00191 00192 // assign new vertex position 00193 00194 v0.pos = new_vertex; 00195 v1.pos = new_vertex; 00196 00197 // assign the new vertex color 00198 00199 m_color_editor.SetColor(new_color,v0ind); 00200 m_color_editor.SetColor(new_color,v1ind); 00201 00202 // sum the quadrics of v0 and v1 00203 q0 = sum; 00204 q1 = sum; 00205 00206 // ok update the primitive properties 00207 00208 m_face_editor.Update(m_update_faces); 00209 m_face_editor.UpdateVertexNormals(m_update_vertices); 00210 00211 // update the external vertex buffer 00212 m_extern_editor.CopyModifiedVerts(m_mesh,m_update_vertices); 00213 00214 // update the external face buffer 00215 m_extern_editor.CopyModifiedFaces(m_mesh,m_update_faces); 00216 00217 // update the edge heap 00218 UpdateHeap(m_deg_edges,m_new_edges); 00219 00220 m_quadric_editor->Remove(m_deg_vertices); 00221 m_face_editor.Remove(m_deg_faces); 00222 m_face_editor.RemoveVertexNormals(m_deg_vertices); 00223 m_color_editor.RemoveVertexColors(m_deg_vertices); 00224 00225 // delete the primitives 00226 00227 DeletePrimitives(m_deg_edges,m_deg_faces,m_deg_vertices); 00228 00229 } else { 00230 // the edge could not be collapsed at the moment - so 00231 // we adjust it's priority and add it back to the heap. 00232 m_heap->Remove(edges.begin(),0); 00233 edges[heap_top].HeapKey() = - MT_INFINITY; 00234 m_heap->Insert(edges.begin(),heap_top); 00235 } 00236 00237 //clear all the temporary buffers 00238 00239 m_deg_faces.clear(); 00240 m_deg_edges.clear(); 00241 m_deg_vertices.clear(); 00242 00243 m_update_faces.clear(); 00244 m_update_vertices.clear(); 00245 m_new_edges.clear(); 00246 00247 return true; 00248 00249 } 00250 00251 void 00252 LOD_NdQSDecimator:: 00253 DeletePrimitives( 00254 const vector<LOD_EdgeInd> & degenerate_edges, 00255 const vector<LOD_FaceInd> & degenerate_faces, 00256 const vector<LOD_VertexInd> & degenerate_vertices 00257 ) { 00258 00259 // assumes that the 3 vectors are sorted in descending order. 00260 00261 // Delete Degnerate primitives 00263 00264 00265 // delete the old edges - we have to be very careful here 00266 // mesh.delete() swaps edges to be deleted with the last edge in 00267 // the edge buffer. However the next edge to be deleted may have 00268 // been the last edge in the buffer! 00269 00270 // One way to solve this is to sort degenerate_edges in descending order. 00271 // And then delete them in that order. 00272 00273 // it is also vital that degenerate_edges contains no duplicates 00274 00275 vector<LOD_EdgeInd>::const_iterator edge_it = degenerate_edges.begin(); 00276 vector<LOD_EdgeInd>::const_iterator edge_end = degenerate_edges.end(); 00277 00278 for (; edge_it != edge_end; ++edge_it) { 00279 m_mesh.DeleteEdge(*edge_it,m_heap); 00280 } 00281 00282 00283 00284 vector<LOD_FaceInd>::const_iterator face_it = degenerate_faces.begin(); 00285 vector<LOD_FaceInd>::const_iterator face_end = degenerate_faces.end(); 00286 00287 for (;face_it != face_end; ++face_it) { 00288 m_mesh.DeleteFace(m_extern_editor,*face_it); 00289 } 00290 00291 vector<LOD_VertexInd>::const_iterator vertex_it = degenerate_vertices.begin(); 00292 vector<LOD_VertexInd>::const_iterator vertex_end = degenerate_vertices.end(); 00293 00294 for (;vertex_it != vertex_end; ++vertex_it) { 00295 m_mesh.DeleteVertex(m_extern_editor,*vertex_it); 00296 } 00297 } 00298 00299 00300 bool 00301 LOD_NdQSDecimator:: 00302 BuildHeap( 00303 ){ 00304 // build the geometric quadrics 00305 00306 if (m_quadric_editor->BuildQuadrics(m_face_editor,true) == false) return false; 00307 00308 // add in the property quadrics. 00309 ComputePropertyQuadrics(); 00310 00311 m_quadric_editor->InitializeHeapKeys(m_color_editor); 00312 00313 m_heap = Heap<LOD_Edge>::New(); 00314 // load in edge pointers to the heap 00315 00316 vector<LOD_Edge> & edge_set= m_mesh.EdgeSet(); 00317 vector<LOD_Edge>::const_iterator edge_end = edge_set.end(); 00318 vector<LOD_Edge>::iterator edge_start = edge_set.begin(); 00319 00320 vector<int> & heap_vector = m_heap->HeapVector(); 00321 00322 for (int i = 0; i < edge_set.size(); ++i) { 00323 edge_set[i].HeapPos() = i; 00324 heap_vector.push_back(i); 00325 } 00326 00327 m_heap->MakeHeap(edge_set.begin()); 00328 00329 return true; 00330 } 00331 00332 void 00333 LOD_NdQSDecimator:: 00334 UpdateHeap( 00335 vector<LOD_EdgeInd> °_edges, 00336 vector<LOD_EdgeInd> &new_edges 00337 ){ 00338 // first of all compute values for the new edges 00339 // and bung them on the heap. 00340 00341 vector<LOD_Edge> & edge_set= m_mesh.EdgeSet(); 00342 00343 vector<LOD_EdgeInd>::const_iterator edge_it = new_edges.begin(); 00344 vector<LOD_EdgeInd>::const_iterator end_it = new_edges.end(); 00345 00346 00347 // insert all the new edges 00349 00350 // compute edge costs ffor the new edges 00351 00352 m_quadric_editor->ComputeEdgeCosts(new_edges,m_color_editor); 00353 00354 // inser the new elements into the heap 00355 00356 for (; edge_it != end_it; ++edge_it) { 00357 m_heap->Insert(edge_set.begin(),*edge_it); 00358 } 00359 00360 00361 // remove all the old values from the heap 00362 00363 edge_it = deg_edges.begin(); 00364 end_it = deg_edges.end(); 00365 00366 for (; edge_it != end_it; ++edge_it) { 00367 LOD_Edge &e = edge_set[*edge_it]; 00368 m_heap->Remove(edge_set.begin(),e.HeapPos()); 00369 00370 e.HeapPos() = 0xffffffff; 00371 00372 } 00373 } 00374 00375 void 00376 LOD_NdQSDecimator:: 00377 ComputePropertyQuadrics( 00378 ){ 00379 00380 vector<LOD_TriFace> & faces = m_mesh.FaceSet(); 00381 vector<LOD_Vertex> & verts = m_mesh.VertexSet(); 00382 vector<LOD_NdQuadric> & quadrics = m_quadric_editor->Quadrics(); 00383 const vector<MT_Vector3> &face_normals = m_face_editor.Normals(); 00384 00385 // compute the linear functionals for each face 00386 00387 // For each property associated with that face we compute 00388 // a property gradient, construct a quadric based on this and add 00389 // it to each of the face's vertex quadrics. 00390 00391 vector<LOD_TriFace>::const_iterator f_start = faces.begin(); 00392 vector<LOD_TriFace>::const_iterator f_end = faces.end(); 00393 vector<LOD_TriFace>::iterator f = faces.begin(); 00394 00395 // we need a little matrix space to help us with the 00396 // linear functional computation. 00397 00398 TNT::Matrix<MT_Scalar> mat(4,4,MT_Scalar(0)); 00399 TNT::Vector<MT_Scalar> vec(4,MT_Scalar(1)); 00400 00401 // some pivots. 00402 00403 TNT::Vector<TNT::Subscript> pivots(4,int(0)); 00404 00405 // Quadrics now consume heap memory so let's 00406 // reuse one in the following loop rather than 00407 // making one each iteration. 00408 00409 LOD_NdQuadric qp; 00410 00411 00412 for (;f != f_end; ++f) { 00413 00414 // collect the coordinates of the face 00415 // and the normal into a matrix 00416 00417 const LOD_VertexInd * f_verts= f->m_verts; 00418 00419 const MT_Vector3 & p0 = verts[f_verts[0]].pos; 00420 const MT_Vector3 & p1 = verts[f_verts[1]].pos; 00421 const MT_Vector3 & p2 = verts[f_verts[2]].pos; 00422 00423 const MT_Vector3 c0 = m_color_editor.IndexColor(f_verts[0]); 00424 const MT_Vector3 c1 = m_color_editor.IndexColor(f_verts[1]); 00425 const MT_Vector3 c2 = m_color_editor.IndexColor(f_verts[2]); 00426 00427 // get the face normal 00428 00429 const MT_Vector3 & fn = face_normals[int(f - f_start)]; 00430 00431 // load into mat 00432 00433 int i; 00434 for (i = 0; i < 3; i++) { 00435 mat[0][i] = p0[i]; 00436 mat[1][i] = p1[i]; 00437 mat[2][i] = p2[i]; 00438 mat[3][i] = fn[i]; 00439 } 00440 mat[0][3] = MT_Scalar(1); 00441 mat[1][3] = MT_Scalar(1); 00442 mat[2][3] = MT_Scalar(1); 00443 mat[3][3] = MT_Scalar(0); 00444 00445 // Compute the pivots 00446 00447 if (TNT::LU_factor(mat,pivots)) { 00448 // bad face! 00449 continue; 00450 } 00451 00452 // compute red linear functional 00453 00454 vec[0] = c0[0]; 00455 vec[1] = c1[0]; 00456 vec[2] = c2[0]; 00457 vec[3] = MT_Scalar(0); 00458 00459 TNT::LU_solve(mat,pivots,vec); 00460 00461 // construct a quadric based on this functional 00462 00463 qp = LOD_NdQuadric( 00464 MT_Vector3(vec[0],vec[1],vec[2]), 00465 vec[3], 00466 0 00467 ); 00468 // compute green functional 00469 00470 vec[0] = c0[1]; 00471 vec[1] = c1[1]; 00472 vec[2] = c2[1]; 00473 vec[3] = MT_Scalar(0); 00474 00475 TNT::LU_solve(mat,pivots,vec); 00476 00477 // construct a quadric based on this functional 00478 00479 qp += LOD_NdQuadric( 00480 MT_Vector3(vec[0],vec[1],vec[2]), 00481 vec[3], 00482 1 00483 ); 00484 00485 // compute blue functional 00486 00487 vec[0] = c0[2]; 00488 vec[1] = c1[2]; 00489 vec[2] = c2[2]; 00490 vec[3] = MT_Scalar(0); 00491 00492 TNT::LU_solve(mat,pivots,vec); 00493 00494 // construct a quadric based on this functional 00495 00496 qp += LOD_NdQuadric( 00497 MT_Vector3(vec[0],vec[1],vec[2]), 00498 vec[3], 00499 2 00500 ); 00501 00502 // add to the geometric quadrics of each of the 00503 // vertices of f 00504 00505 qp *= MT_Scalar(50); 00506 00507 00508 quadrics[f_verts[0]] += qp; 00509 quadrics[f_verts[1]] += qp; 00510 quadrics[f_verts[2]] += qp; 00511 00512 qp.Clear(); 00513 00514 } 00515 } 00516 00517 00518