55 #include <OpenMesh/Core/IO/MeshIO.hh> 56 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh> 57 #include <OpenMesh/Core/Utils/Endian.hh> 59 #include <OpenMesh/Tools/Utils/getopt.h> 61 #include <OpenMesh/Tools/VDPM/StreamingDef.hh> 62 #include <OpenMesh/Tools/VDPM/ViewingParameters.hh> 63 #include <OpenMesh/Tools/VDPM/VHierarchy.hh> 64 #include <OpenMesh/Tools/VDPM/VFront.hh> 96 {
return node_handle_; }
99 { node_handle_ = _node_handle; }
116 vhierarchy_leaf_node_handle()
117 {
return leaf_node_handle_; }
121 { leaf_node_handle_ = _leaf_node_handle; }
145 Mesh::VertexHandle v0, v1, vl, vr;
148 typedef std::vector<PMInfo> PMInfoContainer;
149 typedef PMInfoContainer::iterator PMInfoIter;
150 typedef std::vector<VertexHandle> VertexHandleContainer;
151 typedef std::vector<Vec3f> ResidualContainer;
157 void open_prog_mesh(
const std::string &_filename);
160 void save_vd_prog_mesh(
const std::string &_filename);
164 void locate_fund_cut_vertices();
166 void create_vertex_hierarchy();
170 void refine(
unsigned int _n);
173 void coarsen(
unsigned int _n);
175 void vdpm_analysis();
178 VHierarchyNodeHandleContainer &leaf_nodes);
180 VHierarchyNodeHandleContainer &leaf_nodes);
182 VHierarchyNodeHandleContainer &leaf_nodes);
184 VHierarchyNodeHandleContainer &leaf_nodes);
186 ResidualContainer &residuals);
189 point2triangle_residual(
const Vec3f &p,
190 const Vec3f tri[3],
float &s,
float &t);
193 void PrintOutFundCuts();
194 void PrintVertexNormals();
200 PMInfoContainer pminfos_;
205 unsigned int n_base_vertices_, n_base_faces_, n_details_;
206 unsigned int n_current_res_;
207 unsigned int n_max_res_;
208 bool verbose =
false;
213 void usage_and_exit(
int xcode)
217 cout <<
"Usage: vdpmanalyzer [-h] [-o output.spm] input.pm\n";
226 replace_extension( std::string& _s,
const std::string& _e )
228 std::string::size_type
dot = _s.rfind(
".");
229 if (dot == std::string::npos)
232 { _s = _s.substr(0,dot+1)+_e; }
240 basename(
const std::string& _f)
242 std::string::size_type
dot = _f.rfind(
"/");
243 if (dot == std::string::npos)
245 return _f.substr(dot+1, _f.length()-(dot+1));
252 typedef std::vector<OpenMesh::Vec3f> MyPoints;
253 typedef MyPoints::iterator MyPointsIter;
255 MyPoints projected_points;
256 MyPoints original_points;
262 int main(
int argc,
char **argv)
268 while ( (c=getopt(argc, argv,
"o:"))!=-1 )
272 case 'v': verbose =
true;
break;
273 case 'o': ofname = optarg;
break;
274 case 'h': usage_and_exit(0);
break;
275 default: usage_and_exit(1);
282 ifname = argv[optind];
284 if (ofname ==
"." || ofname ==
".." )
285 ofname +=
"/" + basename(ifname);
286 std::string spmfname = ofname.empty() ? ifname : ofname;
287 replace_extension(spmfname,
"spm");
289 if ( ifname.empty() || spmfname.empty() )
296 open_prog_mesh(ifname);
298 save_vd_prog_mesh(spmfname);
300 catch( std::bad_alloc& )
302 std::cerr <<
"Error: out of memory!\n" << std::endl;
305 catch( std::exception& x )
307 std::cerr <<
"Error: " << x.what() << std::endl;
312 std::cerr <<
"Fatal! Unknown error!\n";
322 open_prog_mesh(
const std::string& _filename)
325 unsigned int i, i0, i1, i2;
326 unsigned int v1, vl, vr;
332 std::ifstream ifs(_filename.c_str(), std::ios::binary);
335 std::cerr <<
"read error\n";
343 ifs.read(c, 8); c[8] =
'\0';
344 if (std::string(c) != std::string(
"ProgMesh"))
346 std::cerr <<
"Wrong file format.\n";
350 IO::restore(ifs, n_base_vertices_, swap);
351 IO::restore(ifs, n_base_faces_, swap);
352 IO::restore(ifs, n_details_, swap);
354 vhierarchy_.set_num_roots(n_base_vertices_);
356 for (i=0; i<n_base_vertices_; ++i)
358 IO::restore(ifs, p, swap);
361 node_index = vhierarchy_.generate_node_index(i, 1);
362 node_handle = vhierarchy_.add_node();
364 vhierarchy_.node(node_handle).set_index(node_index);
365 vhierarchy_.node(node_handle).set_vertex_handle(vertex_handle);
366 mesh_.data(vertex_handle).set_vhierarchy_node_handle(node_handle);
369 for (i=0; i<n_base_faces_; ++i)
371 IO::restore(ifs, i0, swap);
372 IO::restore(ifs, i1, swap);
373 IO::restore(ifs, i2, swap);
374 mesh_.add_face(mesh_.vertex_handle(i0),
375 mesh_.vertex_handle(i1),
376 mesh_.vertex_handle(i2));
380 for (i=0; i<n_details_; ++i)
382 IO::restore(ifs, p, swap);
383 IO::restore(ifs, v1, swap);
384 IO::restore(ifs, vl, swap);
385 IO::restore(ifs, vr, swap);
390 pminfo.v1 = Mesh::VertexHandle(v1);
391 pminfo.vl = Mesh::VertexHandle(vl);
392 pminfo.vr = Mesh::VertexHandle(vr);
393 pminfos_.push_back(pminfo);
395 node_handle = mesh_.data(pminfo.v1).vhierarchy_node_handle();
397 vhierarchy_.make_children(node_handle);
398 lchild_handle = vhierarchy_.lchild_handle(node_handle);
399 rchild_handle = vhierarchy_.rchild_handle(node_handle);
401 mesh_.data(pminfo.v0).set_vhierarchy_node_handle(lchild_handle);
402 mesh_.data(pminfo.v1).set_vhierarchy_node_handle(rchild_handle);
403 vhierarchy_.node(lchild_handle).set_vertex_handle(pminfo.v0);
404 vhierarchy_.node(rchild_handle).set_vertex_handle(pminfo.v1);
411 for (i=0; i<n_base_vertices_; ++i)
413 node_handle = vhierarchy_.root_handle(i);
414 vertex_handle = vhierarchy_.node(node_handle).vertex_handle();
416 mesh_.data(vertex_handle).set_vhierarchy_node_handle(node_handle);
419 pmiter_ = pminfos_.begin();
421 n_max_res_ = n_details_;
429 Mesh::ConstVertexIter
430 vIt(mesh_.vertices_begin()),
431 vEnd(mesh_.vertices_end());
433 Mesh::Point bbMin, bbMax;
435 bbMin = bbMax = mesh_.point(*vIt);
436 for (; vIt!=vEnd; ++vIt)
438 bbMin.minimize(mesh_.point(*vIt));
439 bbMax.maximize(mesh_.point(*vIt));
443 std::cerr << mesh_.n_vertices() <<
" vertices, " 444 << mesh_.n_edges() <<
" edge, " 445 << mesh_.n_faces() <<
" faces, " 446 << n_details_ <<
" detail vertices\n";
453 save_vd_prog_mesh(
const std::string &_filename)
459 float radius, sin_square, mue_square, sigma_square;
461 Mesh::HalfedgeHandle hh;
462 Mesh::VertexHandle vh;
466 std::map<VertexHandle, unsigned int> handle2index_map;
468 std::ofstream ofs(_filename.c_str(), std::ios::binary);
471 std::cerr <<
"write error\n";
481 IO::store(ofs, n_base_vertices_, swap);
482 IO::store(ofs, n_base_faces_, swap);
483 IO::store(ofs, n_details_, swap);
487 mesh_.garbage_collection(
false,
true,
true );
489 for (i=0; i<n_base_vertices_; ++i)
491 node_handle = vhierarchy_.root_handle(i);
492 vh = vhierarchy_.node(node_handle).vertex_handle();
495 radius = vhierarchy_.node(node_handle).radius();
496 normal = vhierarchy_.node(node_handle).normal();
497 sin_square = vhierarchy_.node(node_handle).sin_square();
498 mue_square = vhierarchy_.node(node_handle).mue_square();
499 sigma_square = vhierarchy_.node(node_handle).sigma_square();
501 IO::store(ofs, p, swap);
502 IO::store(ofs, radius, swap);
503 IO::store(ofs, normal, swap);
504 IO::store(ofs, sin_square, swap);
505 IO::store(ofs, mue_square, swap);
506 IO::store(ofs, sigma_square, swap);
508 handle2index_map[vh] = i;
512 for (f_it=mesh_.faces_begin(); f_it!=mesh_.faces_end(); ++f_it) {
513 hh = mesh_.halfedge_handle(*f_it);
514 vh = mesh_.to_vertex_handle(hh);
515 fvi[0] = handle2index_map[vh];
517 hh = mesh_.next_halfedge_handle(hh);
518 vh = mesh_.to_vertex_handle(hh);
519 fvi[1] = handle2index_map[vh];
521 hh = mesh_.next_halfedge_handle(hh);
522 vh = mesh_.to_vertex_handle(hh);
523 fvi[2] = handle2index_map[vh];
525 IO::store(ofs, fvi[0], swap);
526 IO::store(ofs, fvi[1], swap);
527 IO::store(ofs, fvi[2], swap);
533 for (i=0; i<n_details_; ++i)
535 PMInfo pminfo = *pmiter_;
537 p = mesh_.point(pminfo.v0);
539 IO::store(ofs, p, swap);
542 node_handle = mesh_.data(pminfo.v1).vhierarchy_node_handle();
543 lchild_handle = vhierarchy_.lchild_handle(node_handle);
544 rchild_handle = vhierarchy_.rchild_handle(node_handle);
546 node_index = vhierarchy_.node(node_handle).node_index();
547 fund_lcut_index = vhierarchy_.node(node_handle).fund_lcut_index();
548 fund_rcut_index = vhierarchy_.node(node_handle).fund_rcut_index();
550 IO::store(ofs, node_index.value(), swap);
551 IO::store(ofs, fund_lcut_index.value(), swap);
552 IO::store(ofs, fund_rcut_index.value(), swap);
554 radius = vhierarchy_.node(lchild_handle).radius();
555 normal = vhierarchy_.node(lchild_handle).normal();
556 sin_square = vhierarchy_.node(lchild_handle).sin_square();
557 mue_square = vhierarchy_.node(lchild_handle).mue_square();
558 sigma_square = vhierarchy_.node(lchild_handle).sigma_square();
560 IO::store(ofs, radius, swap);
561 IO::store(ofs, normal, swap);
562 IO::store(ofs, sin_square, swap);
563 IO::store(ofs, mue_square, swap);
564 IO::store(ofs, sigma_square, swap);
566 radius = vhierarchy_.node(rchild_handle).radius();
567 normal = vhierarchy_.node(rchild_handle).normal();
568 sin_square = vhierarchy_.node(rchild_handle).sin_square();
569 mue_square = vhierarchy_.node(rchild_handle).mue_square();
570 sigma_square = vhierarchy_.node(rchild_handle).sigma_square();
572 IO::store(ofs, radius, swap);
573 IO::store(ofs, normal, swap);
574 IO::store(ofs, sin_square, swap);
575 IO::store(ofs, mue_square, swap);
576 IO::store(ofs, sigma_square, swap);
583 std::cout <<
"save view-dependent progressive mesh" << std::endl;
588 void refine(
unsigned int _n)
590 while (n_current_res_ < _n && pmiter_ != pminfos_.end())
598 parent_handle = mesh_.data(pmiter_->v1).vhierarchy_node_handle();
601 lchild_handle = vhierarchy_.lchild_handle(parent_handle),
602 rchild_handle = vhierarchy_.rchild_handle(parent_handle);
604 mesh_.data(pmiter_->v0).set_vhierarchy_node_handle(lchild_handle);
605 mesh_.data(pmiter_->v1).set_vhierarchy_node_handle(rchild_handle);
616 void coarsen(
unsigned int _n)
618 while (n_current_res_ > _n && pmiter_ != pminfos_.begin())
622 Mesh::HalfedgeHandle hh =
623 mesh_.find_halfedge(pmiter_->v0, pmiter_->v1);
627 rchild_handle = mesh_.data(pmiter_->v1).vhierarchy_node_handle();
630 parent_handle = vhierarchy_.parent_handle(rchild_handle);
632 mesh_.data(pmiter_->v1).set_vhierarchy_node_handle(parent_handle);
646 Mesh::VertexHandle vh;
647 Mesh::VertexIter v_it;
648 Mesh::HalfedgeIter h_it;
649 Mesh::HalfedgeHandle h, o, hn, op, hpo, on, ono;
650 VHierarchyNodeHandleContainer leaf_nodes;
660 std::cout <<
"Init view-dependent PM analysis" << std::endl;
663 for (h_it=mesh_.halfedges_begin(); h_it!=mesh_.halfedges_end(); ++h_it)
665 vh = mesh_.to_vertex_handle(*h_it);
666 mesh_.data(*h_it).set_vhierarchy_leaf_node_handle(mesh_.data(vh).vhierarchy_node_handle());
669 for (v_it=mesh_.vertices_begin(); v_it!=mesh_.vertices_end(); ++v_it)
672 node_handle = mesh_.data(*v_it).vhierarchy_node_handle();
674 vhierarchy_.node(node_handle).set_normal(mesh_.normal(*v_it));
677 std::cout <<
"Start view-dependent PM analysis" << std::endl;
682 for (i=n_max_res_; i>0; --i)
685 PMInfo pminfo = pminfos_[i-1];
688 std::cout <<
"Analyzing " << i <<
"-th detail vertex" << std::endl;
691 h = mesh_.find_halfedge(pminfo.v0, pminfo.v1);
692 o = mesh_.opposite_halfedge_handle(h);
693 hn = mesh_.next_halfedge_handle(h);
694 hpo = mesh_.opposite_halfedge_handle(mesh_.prev_halfedge_handle(h));
695 op = mesh_.prev_halfedge_handle(o);
696 on = mesh_.next_halfedge_handle(o);
697 ono = mesh_.opposite_halfedge_handle(on);
700 rchild_handle = mesh_.data(pminfo.v1).vhierarchy_node_handle();
703 parent_handle = vhierarchy_.parent_handle(rchild_handle);
705 if (pminfo.vl != Mesh::InvalidVertexHandle)
708 fund_lcut_handle = mesh_.data(hn).vhierarchy_leaf_node_handle();
711 left_leaf_handle = mesh_.data(hpo).vhierarchy_leaf_node_handle();
713 mesh_.data(hn).set_vhierarchy_leaf_node_handle(left_leaf_handle);
715 vhierarchy_.node(parent_handle).
716 set_fund_lcut(vhierarchy_.node_index(fund_lcut_handle));
719 if (pminfo.vr != Mesh::InvalidVertexHandle)
722 fund_rcut_handle = mesh_.data(on).vhierarchy_leaf_node_handle(),
723 right_leaf_handle = mesh_.data(ono).vhierarchy_leaf_node_handle();
725 mesh_.data(op).set_vhierarchy_leaf_node_handle(right_leaf_handle);
727 vhierarchy_.node(parent_handle).
728 set_fund_rcut(vhierarchy_.node_index(fund_rcut_handle));
735 get_leaf_node_handles(parent_handle, leaf_nodes);
736 compute_bounding_box(parent_handle, leaf_nodes);
737 compute_cone_of_normals(parent_handle, leaf_nodes);
738 compute_screen_space_error(parent_handle, leaf_nodes);
744 std::cout <<
" radius of bounding sphere: " 745 << vhierarchy_.node(parent_handle).radius() << std::endl;
746 std::cout <<
" direction of cone of normals: " 747 << vhierarchy_.node(parent_handle).normal() << std::endl;
748 std::cout <<
" sin(semi-angle of cone of normals) ^2: " 749 << vhierarchy_.node(parent_handle).sin_square() << std::endl;
750 std::cout <<
" (mue^2, sigma^2) : (" 751 << vhierarchy_.node(parent_handle).mue_square() <<
", " 752 << vhierarchy_.node(parent_handle).sigma_square() <<
")" 754 std::cout <<
"- " << t.
as_string() << std::endl;
760 std::cout <<
"Analyzing step completed in " 769 VHierarchyNodeHandleContainer &leaf_nodes)
771 if (vhierarchy_.node(node_handle).
is_leaf())
773 leaf_nodes.push_back(node_handle);
777 get_leaf_node_handles(vhierarchy_.node(node_handle).
lchild_handle(),
779 get_leaf_node_handles(vhierarchy_.node(node_handle).
rchild_handle(),
788 compute_bounding_box(
VHierarchyNodeHandle node_handle, VHierarchyNodeHandleContainer &leaf_nodes)
792 VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end());
795 VertexHandle vh = vhierarchy_.node(node_handle).vertex_handle();
797 for ( n_it = leaf_nodes.begin(); n_it != n_end; ++n_it )
799 lp = mesh_.point(vhierarchy_.vertex_handle(*n_it));
800 max_distance = std::max(max_distance, (p - lp).length());
803 vhierarchy_.node(node_handle).set_radius(max_distance);
811 VHierarchyNodeHandleContainer &leaf_nodes)
814 VertexHandle vh = vhierarchy_.node(node_handle).vertex_handle();
815 VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end());
818 float max_angle = 0.0f;
820 n_it = leaf_nodes.begin();
821 while( n_it != n_end )
823 ln = vhierarchy_.node(*n_it).normal();
824 const float angle = acosf(
dot(n,ln) );
825 max_angle = std::max(max_angle, angle );
830 max_angle = std::min(max_angle,
float(M_PI_2));
831 mesh_.set_normal(vh, n);
832 vhierarchy_.node(node_handle).set_normal(n);
833 vhierarchy_.node(node_handle).set_semi_angle(max_angle);
840 compute_screen_space_error(
VHierarchyNodeHandle node_handle, VHierarchyNodeHandleContainer &leaf_nodes)
842 std::vector<Vec3f> residuals;
844 Mesh::HalfedgeHandle heh;
845 Mesh::VertexHandle vh;
849 #if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) ) 851 Vec3f tri[3]{ {},{},{} };
856 VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end());
858 for ( n_it = leaf_nodes.begin(); n_it != n_end; ++n_it )
860 lp = mesh_.point(vhierarchy_.node(*n_it).vertex_handle());
863 vh = vhierarchy_.node(node_handle).vertex_handle();
864 residual = lp - mesh_.point(vh);
865 float min_distance = residual.
length();
867 for (vf_it=mesh_.vf_iter(vh); vf_it.is_valid(); ++vf_it)
869 heh = mesh_.halfedge_handle(*vf_it);
870 tri[0] = mesh_.point(mesh_.to_vertex_handle(heh));
871 heh = mesh_.next_halfedge_handle(heh);
872 tri[1] = mesh_.point(mesh_.to_vertex_handle(heh));
873 heh = mesh_.next_halfedge_handle(heh);
874 tri[2] = mesh_.point(mesh_.to_vertex_handle(heh));
876 res = point2triangle_residual(lp, tri, s, t);
878 if (res.
length() < min_distance)
881 min_distance = res.
length();
885 residuals.push_back(residual);
888 compute_mue_sigma(node_handle, residuals);
896 ResidualContainer &residuals)
899 float max_inner, max_cross;
900 ResidualContainer::iterator r_it, r_end(residuals.end());
902 max_inner = max_cross = 0.0f;
903 vn = mesh_.normal(vhierarchy_.node(node_handle).vertex_handle());
904 for (r_it = residuals.begin(); r_it != r_end; ++r_it)
906 float inner = fabsf(
dot(*r_it, vn));
909 max_inner = std::max(max_inner, inner);
910 max_cross = std::max(max_cross, cross);
913 if (max_cross < 1.0e-7)
915 vhierarchy_.node(node_handle).set_mue(max_cross);
916 vhierarchy_.node(node_handle).set_sigma(max_inner);
919 float ratio = std::max(1.0f, max_inner/max_cross);
920 float whole_degree = acosf(1.0f/ratio);
925 for (r_it = residuals.begin(); r_it != r_end; ++r_it)
928 float res_length = res.
length();
931 float degree = acosf(
dot(vn,res) / res_length);
933 if (degree < 0.0f) degree = -degree;
934 if (degree >
float(M_PI_2)) degree = float(M_PI) - degree;
936 if (degree < whole_degree)
937 mue = cosf(whole_degree - degree) * res_length;
941 max_mue = std::max(max_mue, mue);
944 vhierarchy_.node(node_handle).set_mue(max_mue);
945 vhierarchy_.node(node_handle).set_sigma(ratio*max_mue);
953 point2triangle_residual(
const Vec3f &p,
const Vec3f tri[3],
float &s,
float &t)
959 float a =
dot(E0, E0);
960 float b =
dot(E0, E1);
961 float c =
dot(E1, E1);
962 float d =
dot(E0, D);
963 float e =
dot(E1, D);
965 float det = fabsf(a*c - b*b);
1033 else if ( t < 0.0f )
1055 float inv_det = 1.0f/det;
1063 float tmp0, tmp1, numer, denom;
1071 numer = tmp1 - tmp0;
1073 if ( numer >= denom )
1094 else if ( e >= 0.0f )
1106 else if ( t < 0.0f )
1112 numer = tmp1 - tmp0;
1114 if ( numer >= denom )
1135 else if ( d >= 0.0f )
1149 numer = c + e - b - d;
1150 if ( numer <= 0.0f )
1159 if ( numer >= denom )
1175 residual = p - (B + s*E0 + t*E1);
VHierarchyNodeHandle rchild_handle()
Returns handle to right child.
osg::Vec3f cross(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
Kernel::VertexFaceIter VertexFaceIter
Circulator.
Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits.
T angle(T _cos_angle, T _sin_angle)
std::string as_string(Format format=Automatic)
Handle for a vertex entity.
Add status to mesh item (all items)
HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, VertexHandle _vl, VertexHandle _vr)
Vertex Split: inverse operation to collapse().
#define VertexTraits
Macro for defining the vertex traits. See Specifying your MyMesh.
Add normals to mesh item (vertices/faces)
void stop(void)
Stop measurement.
#define VertexAttributes(_i)
Macro for defining the vertex attributes. See Specifying your MyMesh.
Little endian (Intel family and clones)
VHierarchyNodeHandle lchild_handle()
Returns handle to left child.
#define EdgeAttributes(_i)
Macro for defining the edge attributes. See Specifying your MyMesh.
void update_vertex_normals()
Update normal vectors for all vertices.
SmartVertexHandle add_vertex(const Point &_p)
Alias for new_vertex(const Point&).
bool is_leaf() const
Returns true, if node is leaf else false.
void update_face_normals()
Update normal vectors for all faces.
auto length() const -> decltype(std::declval< VectorT< S, DIM >>().norm())
compute squared euclidean norm
#define HalfedgeTraits
Macro for defining the halfedge traits. See Specifying your MyMesh.
void start(void)
Start measurement.
#define HalfedgeAttributes(_i)
Macro for defining the halfedge attributes. See Specifying your MyMesh.
std::vector< VHierarchyNodeHandle > VHierarchyNodeHandleContainer
Container for vertex hierarchy node handles.
#define FaceAttributes(_i)
Macro for defining the face attributes. See Specifying your MyMesh.
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
static Type local()
Return endian type of host system.
Normal calc_vertex_normal(VertexHandle _vh) const
Calculate vertex normal for one specific vertex.