Panda3D
|
00001 // Filename: qtessSurface.cxx 00002 // Created by: drose (13Oct03) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "qtessSurface.h" 00016 #include "qtessGlobals.h" 00017 #include "qtessInputEntry.h" 00018 #include "config_egg_qtess.h" 00019 #include "eggPolygon.h" 00020 #include "eggVertexPool.h" 00021 #include "eggVertex.h" 00022 #include "eggComment.h" 00023 #include "egg_parametrics.h" 00024 #include "pset.h" 00025 #include "pmap.h" 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: QtessSurface::Constructor 00029 // Access: Public 00030 // Description: 00031 //////////////////////////////////////////////////////////////////// 00032 QtessSurface:: 00033 QtessSurface(EggNurbsSurface *egg_surface) : 00034 _egg_surface(egg_surface) 00035 { 00036 _nurbs = make_nurbs_surface(_egg_surface, LMatrix4d::ident_mat()); 00037 _has_vertex_color = _egg_surface->has_vertex_color(); 00038 00039 // The first four slots are reserved for vertex color. 00040 _next_d = 4; 00041 00042 _importance = 1.0; 00043 _importance2 = 1.0; 00044 _match_u = _match_v = NULL; 00045 _tess_u = _tess_v = 0; 00046 _got_scores = false; 00047 00048 // If the surface is closed in either dimension, the mininum 00049 // tesselation in that dimension is by default 3, so we don't 00050 // ribbonize the surface. Otherwise the minimum is 1. 00051 _min_u = _min_v = 1; 00052 if (egg_surface->is_closed_u()) { 00053 _min_u = 3; 00054 } 00055 if (egg_surface->is_closed_v()) { 00056 _min_v = 3; 00057 } 00058 00059 if (_nurbs == (NurbsSurfaceEvaluator *)NULL) { 00060 _num_u = _num_v = 0; 00061 00062 } else { 00063 record_vertex_extras(); 00064 00065 _nurbs->normalize_u_knots(); 00066 _nurbs->normalize_v_knots(); 00067 _nurbs_result = _nurbs->evaluate(); 00068 00069 _num_u = _nurbs->get_num_u_segments(); 00070 _num_v = _nurbs->get_num_v_segments(); 00071 00072 if (QtessGlobals::_respect_egg) { 00073 if (egg_surface->get_u_subdiv() != 0) { 00074 _num_u = egg_surface->get_u_subdiv(); 00075 } 00076 if (egg_surface->get_v_subdiv() != 0) { 00077 _num_v = egg_surface->get_v_subdiv(); 00078 } 00079 } 00080 } 00081 } 00082 00083 //////////////////////////////////////////////////////////////////// 00084 // Function: get_score 00085 // Access: Public 00086 // Description: Computes the curvature/stretch score for the surface, 00087 // if it has not been already computed, and returns the 00088 // net surface score. This is used both for 00089 // automatically distributing isoparams among the 00090 // surfaces by curvature, as well as for automatically 00091 // placing the isoparams within each surface by 00092 // curvature. 00093 //////////////////////////////////////////////////////////////////// 00094 double QtessSurface:: 00095 get_score(double ratio) { 00096 if (_nurbs == (NurbsSurfaceEvaluator *)NULL) { 00097 return 0.0; 00098 } 00099 00100 if (!_got_scores) { 00101 _u_placer.get_scores(_nurbs->get_num_u_segments() * 100, 00102 _nurbs->get_num_v_segments() * 2, 00103 ratio, _nurbs_result, true); 00104 _v_placer.get_scores(_nurbs->get_num_v_segments() * 100, 00105 _nurbs->get_num_u_segments() * 2, 00106 ratio, _nurbs_result, false); 00107 _got_scores = true; 00108 } 00109 00110 return _u_placer.get_total_score() * _v_placer.get_total_score() * _importance2; 00111 } 00112 00113 //////////////////////////////////////////////////////////////////// 00114 // Function: QtessSurface::tesselate 00115 // Access: Public 00116 // Description: Applies the appropriate tesselation to the surface, 00117 // and replaces its node in the tree with an EggGroup 00118 // containing both the new vertex pool and all of the 00119 // polygons. 00120 //////////////////////////////////////////////////////////////////// 00121 int QtessSurface:: 00122 tesselate() { 00123 apply_match(); 00124 int tris = 0; 00125 00126 PT(EggGroup) group = do_uniform_tesselate(tris); 00127 PT(EggNode) new_node = group.p(); 00128 if (new_node == (EggNode *)NULL) { 00129 new_node = new EggComment(_egg_surface->get_name(), 00130 "Omitted NURBS surface."); 00131 tris = 0; 00132 } 00133 EggGroupNode *parent = _egg_surface->get_parent(); 00134 nassertr(parent != (EggGroupNode *)NULL, 0); 00135 parent->remove_child(_egg_surface); 00136 parent->add_child(new_node); 00137 00138 return tris; 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: QtessSurface::write_qtess_parameter 00143 // Access: Public 00144 // Description: Writes a line to the given output file telling qtess 00145 // how this surface should be tesselated uniformly. 00146 // Returns the number of tris. 00147 //////////////////////////////////////////////////////////////////// 00148 int QtessSurface:: 00149 write_qtess_parameter(ostream &out) { 00150 apply_match(); 00151 00152 if (_tess_u == 0 || _tess_v == 0) { 00153 out << get_name() << " : omit\n"; 00154 00155 } else if (_iso_u.empty() || _iso_v.empty()) { 00156 out << get_name() << " : " << _tess_u << " " << _tess_v << "\n"; 00157 00158 } else { 00159 out << get_name() << " : " << _iso_u.back() << " " << _iso_v.back(); 00160 QtessInputEntry::output_extra(out, _iso_u, 'u'); 00161 QtessInputEntry::output_extra(out, _iso_v, 'v'); 00162 out << "\n"; 00163 } 00164 00165 return count_tris(); 00166 } 00167 00168 00169 //////////////////////////////////////////////////////////////////// 00170 // Function: QtessSurface::omit 00171 // Access: Public 00172 // Description: Sets up the surface to omit itself from the output. 00173 //////////////////////////////////////////////////////////////////// 00174 void QtessSurface:: 00175 omit() { 00176 _tess_u = 0; 00177 _tess_v = 0; 00178 } 00179 00180 //////////////////////////////////////////////////////////////////// 00181 // Function: QtessSurface::tesselate_uv 00182 // Access: Public 00183 // Description: Sets the surface up to tesselate itself uniformly at 00184 // u x v, or if autoplace is true, automatically with u 00185 // x v quads. 00186 //////////////////////////////////////////////////////////////////// 00187 void QtessSurface:: 00188 tesselate_uv(int u, int v, bool autoplace, double ratio) { 00189 _tess_u = u; 00190 _tess_v = v; 00191 _iso_u.clear(); 00192 _iso_v.clear(); 00193 if (autoplace) { 00194 tesselate_auto(_tess_u, _tess_v, ratio); 00195 } 00196 } 00197 00198 //////////////////////////////////////////////////////////////////// 00199 // Function: QtessSurface::tesselate_specific 00200 // Access: Public 00201 // Description: Sets the surface up to tesselate itself at specific 00202 // isoparams only. 00203 //////////////////////////////////////////////////////////////////// 00204 void QtessSurface:: 00205 tesselate_specific(const pvector<double> &u_list, 00206 const pvector<double> &v_list) { 00207 _iso_u = u_list; 00208 _iso_v = v_list; 00209 _tess_u = (int)_iso_u.size() - 1; 00210 _tess_v = (int)_iso_v.size() - 1; 00211 } 00212 00213 //////////////////////////////////////////////////////////////////// 00214 // Function: QtessSurface::tesselate_per_isoparam 00215 // Access: Public 00216 // Description: Sets the surface up to tesselate itself to a uniform 00217 // amount per isoparam. 00218 //////////////////////////////////////////////////////////////////// 00219 void QtessSurface:: 00220 tesselate_per_isoparam(double pi, bool autoplace, double ratio) { 00221 if (_num_u == 0 || _num_v == 0) { 00222 omit(); 00223 00224 } else { 00225 _tess_u = max(_min_u, (int)floor(_num_u * _importance * pi + 0.5)); 00226 _tess_v = max(_min_v, (int)floor(_num_v * _importance * pi + 0.5)); 00227 _iso_u.clear(); 00228 _iso_v.clear(); 00229 if (autoplace) { 00230 tesselate_auto(_tess_u, _tess_v, ratio); 00231 } 00232 } 00233 } 00234 00235 00236 //////////////////////////////////////////////////////////////////// 00237 // Function: QtessSurface::TesselatePerScore 00238 // Access: Public 00239 // Description: Sets the surface up to tesselate itself according to 00240 // its computed curvature score in both dimensions. 00241 //////////////////////////////////////////////////////////////////// 00242 void QtessSurface:: 00243 tesselate_per_score(double pi, bool autoplace, double ratio) { 00244 if (get_score(ratio) <= 0.0) { 00245 omit(); 00246 00247 } else { 00248 _tess_u = max(_min_u, (int)floor(_u_placer.get_total_score() * _importance * pi + 0.5)); 00249 _tess_v = max(_min_v, (int)floor(_v_placer.get_total_score() * _importance * pi + 0.5)); 00250 _iso_u.clear(); 00251 _iso_v.clear(); 00252 if (autoplace) { 00253 tesselate_auto(_tess_u, _tess_v, ratio); 00254 } 00255 } 00256 } 00257 00258 //////////////////////////////////////////////////////////////////// 00259 // Function: QtessSurface::tesselate_auto 00260 // Access: Public 00261 // Description: Sets the surface up to tesselate itself by 00262 // automatically determining the best place to put the 00263 // indicated u x v isoparams. 00264 //////////////////////////////////////////////////////////////////// 00265 void QtessSurface:: 00266 tesselate_auto(int u, int v, double ratio) { 00267 if (get_score(ratio) <= 0.0) { 00268 omit(); 00269 00270 } else { 00271 _u_placer.place(u, _iso_u); 00272 _v_placer.place(v, _iso_v); 00273 _tess_u = (int)_iso_u.size() - 1; 00274 _tess_v = (int)_iso_v.size() - 1; 00275 } 00276 } 00277 00278 //////////////////////////////////////////////////////////////////// 00279 // Function: QtessSurface::record_vertex_extras 00280 // Access: Private 00281 // Description: Records the joint membership and morph offsets of 00282 // each control vertex in the extra-dimensional space of 00283 // the NURBS, so that we can extract this data out again 00284 // later to apply to the polygon vertices. 00285 //////////////////////////////////////////////////////////////////// 00286 void QtessSurface:: 00287 record_vertex_extras() { 00288 int num_u_vertices = _egg_surface->get_num_u_cvs(); 00289 int num_v_vertices = _egg_surface->get_num_v_cvs(); 00290 00291 for (int ui = 0; ui < num_u_vertices; ui++) { 00292 for (int vi = 0; vi < num_v_vertices; vi++) { 00293 int i = _egg_surface->get_vertex_index(ui, vi); 00294 EggVertex *egg_vertex = _egg_surface->get_vertex(i); 00295 00296 // The joint membership. 00297 EggVertex::GroupRef::const_iterator gi; 00298 for (gi = egg_vertex->gref_begin(); gi != egg_vertex->gref_end(); ++gi) { 00299 EggGroup *joint = (*gi); 00300 int d = get_joint_membership_index(joint); 00301 double membership = joint->get_vertex_membership(egg_vertex); 00302 _nurbs->set_extended_vertex(ui, vi, d, membership); 00303 } 00304 00305 // The xyz morphs. 00306 EggMorphVertexList::const_iterator dxi; 00307 for (dxi = egg_vertex->_dxyzs.begin(); 00308 dxi != egg_vertex->_dxyzs.end(); 00309 ++dxi) { 00310 const string &morph_name = (*dxi).get_name(); 00311 LVector3 delta = LCAST(PN_stdfloat, (*dxi).get_offset()); 00312 int d = get_dxyz_index(morph_name); 00313 _nurbs->set_extended_vertices(ui, vi, d, delta.get_data(), 3); 00314 } 00315 00316 // The rgba morphs. 00317 EggMorphColorList::const_iterator dri; 00318 for (dri = egg_vertex->_drgbas.begin(); 00319 dri != egg_vertex->_drgbas.end(); 00320 ++dri) { 00321 const string &morph_name = (*dri).get_name(); 00322 const LVector4 &delta = (*dri).get_offset(); 00323 int d = get_drgba_index(morph_name); 00324 _nurbs->set_extended_vertices(ui, vi, d, delta.get_data(), 4); 00325 } 00326 } 00327 } 00328 } 00329 00330 //////////////////////////////////////////////////////////////////// 00331 // Function: QtessSurface::apply_match 00332 // Access: Private 00333 // Description: If the surface was set up to copy its tesselation in 00334 // either axis from another surface, makes this copy 00335 // now. 00336 //////////////////////////////////////////////////////////////////// 00337 void QtessSurface:: 00338 apply_match() { 00339 if (_match_u != NULL) { 00340 QtessSurface *m = *_match_u; 00341 if (m == NULL) { 00342 qtess_cat.warning() 00343 << "No surface to match " << get_name() << " to in U.\n"; 00344 } else { 00345 if (qtess_cat.is_debug()) { 00346 qtess_cat.debug() 00347 << "Matching " << get_name() << " in U to " << m->get_name() 00348 << " in " << (_match_u_to_u?'U':'V') << ".\n"; 00349 } 00350 if (_match_u_to_u) { 00351 _tess_u = m->_tess_u; 00352 _iso_u = m->_iso_u; 00353 } else { 00354 _tess_u = m->_tess_v; 00355 _iso_u = m->_iso_v; 00356 } 00357 } 00358 } 00359 00360 if (_match_v != NULL) { 00361 QtessSurface *m = *_match_v; 00362 if (m == NULL) { 00363 qtess_cat.warning() 00364 << "No surface to match " << get_name() << " in V.\n"; 00365 } else { 00366 if (qtess_cat.is_debug()) { 00367 qtess_cat.debug() 00368 << "Matching " << get_name() << " in V to " << m->get_name() 00369 << " in " << (_match_v_to_v?'V':'U') << ".\n"; 00370 } 00371 if (_match_v_to_v) { 00372 _tess_v = m->_tess_v; 00373 _iso_v = m->_iso_v; 00374 } else { 00375 _tess_v = m->_tess_u; 00376 _iso_v = m->_iso_u; 00377 } 00378 } 00379 } 00380 } 00381 00382 //////////////////////////////////////////////////////////////////// 00383 // Function: do_uniform_tesselate 00384 // Access: Private 00385 // Description: Subdivide the surface uniformly according to the 00386 // parameters specified by an earlier call to omit(), 00387 // teseselate_uv(), or tesselate_per_isoparam(). 00388 //////////////////////////////////////////////////////////////////// 00389 PT(EggGroup) QtessSurface:: 00390 do_uniform_tesselate(int &tris) const { 00391 tris = 0; 00392 00393 if (_tess_u == 0 || _tess_v == 0) { 00394 // No tesselation! 00395 if (qtess_cat.is_debug()) { 00396 qtess_cat.debug() 00397 << get_name() << " : omit\n"; 00398 } 00399 return NULL; 00400 } 00401 00402 PT(EggGroup) group = new EggGroup(_egg_surface->get_name()); 00403 00404 // _tess_u and _tess_v are the number of patches to create. Convert 00405 // that to the number of vertices. 00406 00407 int num_u = _tess_u + 1; 00408 int num_v = _tess_v + 1; 00409 00410 if (qtess_cat.is_debug()) { 00411 qtess_cat.debug() << get_name() << " : " << tris << "\n"; 00412 } 00413 00414 assert(_iso_u.empty() || (int)_iso_u.size() == num_u); 00415 assert(_iso_v.empty() || (int)_iso_v.size() == num_v); 00416 00417 // Now how many vertices is that total, and how many vertices per 00418 // strip? 00419 int num_verts = num_u * num_v; 00420 00421 // Create a vertex pool. 00422 PT(EggVertexPool) vpool = new EggVertexPool(_egg_surface->get_name()); 00423 group->add_child(vpool); 00424 00425 // Create all the vertices. 00426 int ui, vi; 00427 double u, v; 00428 00429 typedef pvector<EggVertex *> VertexList; 00430 VertexList new_verts; 00431 new_verts.reserve(num_verts); 00432 00433 // Also collect the vertices into this set to group them by spatial 00434 // position only. This is relevant for calculating normals. 00435 typedef pset<EggVertex *> NVertexGroup; 00436 typedef pmap<LVertexd, NVertexGroup> NVertexCollection; 00437 NVertexCollection n_collection; 00438 00439 for (vi = 0; vi < num_v; vi++) { 00440 if (_iso_v.empty()) { 00441 v = (double)vi / (double)(num_v-1); 00442 } else { 00443 v = _iso_v[vi] / _iso_v.back(); 00444 } 00445 for (ui = 0; ui < num_u; ui++) { 00446 if (_iso_u.empty()) { 00447 u = (double)ui / (double)(num_u-1); 00448 } else { 00449 u = _iso_u[ui] / _iso_u.back(); 00450 } 00451 00452 PT(EggVertex) egg_vertex = evaluate_vertex(u, v); 00453 vpool->add_vertex(egg_vertex); 00454 new_verts.push_back(egg_vertex); 00455 n_collection[egg_vertex->get_pos3()].insert(egg_vertex); 00456 } 00457 } 00458 nassertr((int)new_verts.size() == num_verts, NULL); 00459 00460 // Now create a bunch of quads. 00461 for (vi = 1; vi < num_v; vi++) { 00462 for (ui = 1; ui < num_u; ui++) { 00463 PT(EggPolygon) poly = new EggPolygon; 00464 poly->add_vertex(new_verts[vi*num_u + (ui-1)]); 00465 poly->add_vertex(new_verts[(vi-1)*num_u + (ui-1)]); 00466 poly->add_vertex(new_verts[(vi-1)*num_u + ui]); 00467 poly->add_vertex(new_verts[vi*num_u + ui]); 00468 00469 poly->copy_attributes(*_egg_surface); 00470 00471 // We compute a polygon normal just so we can verify the 00472 // calculated vertex normals. It's also helpful for identifying 00473 // degenerate polygons. 00474 if (poly->recompute_polygon_normal()) { 00475 tris += 2; 00476 group->add_child(poly); 00477 } 00478 } 00479 } 00480 00481 // Now check all the vertex normals by comparing them to the polygon 00482 // normals. Some might have not been computed at all; others might 00483 // be facing in the wrong direction. 00484 00485 // Now go back through and normalize the computed normals. 00486 NVertexCollection::const_iterator nci; 00487 for (nci = n_collection.begin(); nci != n_collection.end(); ++nci) { 00488 const NVertexGroup &group = (*nci).second; 00489 00490 // Calculate the normal these vertices should have based on the 00491 // polygons that share it. 00492 LNormald normal = LNormald::zero(); 00493 int num_polys = 0; 00494 NVertexGroup::const_iterator ngi; 00495 for (ngi = group.begin(); ngi != group.end(); ++ngi) { 00496 EggVertex *egg_vertex = (*ngi); 00497 EggVertex::PrimitiveRef::const_iterator pri; 00498 for (pri = egg_vertex->pref_begin(); 00499 pri != egg_vertex->pref_end(); 00500 ++pri) { 00501 EggPrimitive *egg_primitive = (*pri); 00502 nassertr(egg_primitive->has_normal(), NULL); 00503 normal += egg_primitive->get_normal(); 00504 num_polys++; 00505 } 00506 } 00507 00508 if (num_polys > 0) { 00509 normal /= (double)num_polys; 00510 00511 // Now compare this normal with what the NURBS representation 00512 // calculated. It should be facing in at least vaguely the same 00513 // direction. 00514 for (ngi = group.begin(); ngi != group.end(); ++ngi) { 00515 EggVertex *egg_vertex = (*ngi); 00516 if (egg_vertex->has_normal()) { 00517 if (normal.dot(egg_vertex->get_normal()) < 0.0) { 00518 // This one is backwards. 00519 egg_vertex->set_normal(-egg_vertex->get_normal()); 00520 } 00521 } else { 00522 // This vertex doesn't have a normal; it gets the computed 00523 // normal. 00524 egg_vertex->set_normal(normal); 00525 } 00526 } 00527 } 00528 } 00529 00530 return group; 00531 } 00532 00533 //////////////////////////////////////////////////////////////////// 00534 // Function: evaluate_vertex 00535 // Access: Private 00536 // Description: Evaluates the surface at the given u, v position and 00537 // sets the vertex to the appropriate values. Also sets 00538 // the joint membership of the vertex. 00539 //////////////////////////////////////////////////////////////////// 00540 PT(EggVertex) QtessSurface:: 00541 evaluate_vertex(double u, double v) const { 00542 PT(EggVertex) egg_vertex = new EggVertex; 00543 00544 LVertex point; 00545 LNormal normal; 00546 _nurbs_result->eval_point(u, v, point); 00547 _nurbs_result->eval_normal(u, v, normal); 00548 00549 // If the normal is too short, don't consider it--it's probably 00550 // inaccurate due to numerical limitations. We'll recompute it 00551 // later based on the polygon normals. 00552 PN_stdfloat length = normal.length(); 00553 if (length > 0.0001f) { 00554 normal /= length; 00555 egg_vertex->set_normal(LCAST(double, normal)); 00556 } 00557 00558 egg_vertex->set_pos(LCAST(double, point)); 00559 egg_vertex->set_uv(LVecBase2d(u, v)); 00560 00561 // The color is stored, by convention, in slots 0-4 of the surface. 00562 if (_has_vertex_color) { 00563 LColor rgba; 00564 _nurbs_result->eval_extended_points(u, v, 0, &rgba[0], 4); 00565 egg_vertex->set_color(rgba); 00566 } 00567 00568 // Also fill in the joint membership. 00569 JointTable::const_iterator jti; 00570 for (jti = _joint_table.begin(); jti != _joint_table.end(); ++jti) { 00571 EggGroup *joint = (*jti).first; 00572 int d = (*jti).second; 00573 00574 double membership = _nurbs_result->eval_extended_point(u, v, d); 00575 if (membership > 0.0) { 00576 joint->ref_vertex(egg_vertex, membership); 00577 } 00578 } 00579 00580 // And the morphs. 00581 MorphTable::const_iterator mti; 00582 for (mti = _dxyz_table.begin(); mti != _dxyz_table.end(); ++mti) { 00583 const string &morph_name = (*mti).first; 00584 int d = (*mti).second; 00585 00586 LVector3 delta; 00587 _nurbs_result->eval_extended_points(u, v, d, &delta[0], 3); 00588 if (!delta.almost_equal(LVector3::zero())) { 00589 egg_vertex->_dxyzs.insert(EggMorphVertex(morph_name, LCAST(double, delta))); 00590 } 00591 } 00592 00593 for (mti = _drgba_table.begin(); mti != _drgba_table.end(); ++mti) { 00594 const string &morph_name = (*mti).first; 00595 int d = (*mti).second; 00596 00597 LVector4 delta; 00598 _nurbs_result->eval_extended_points(u, v, d, &delta[0], 4); 00599 if (!delta.almost_equal(LVector4::zero())) { 00600 egg_vertex->_drgbas.insert(EggMorphColor(morph_name, delta)); 00601 } 00602 } 00603 00604 return egg_vertex; 00605 }