Easy3D 2.5.3
Tutorial_601_Tessellator
1/********************************************************************
2 * Copyright (C) 2015 Liangliang Nan <liangliang.nan@gmail.com>
3 * https://3d.bk.tudelft.nl/liangliang/
4 *
5 * This file is part of Easy3D. If it is useful in your research/work,
6 * I would be grateful if you show your appreciation by citing it:
7 * ------------------------------------------------------------------
8 * Liangliang Nan.
9 * Easy3D: a lightweight, easy-to-use, and efficient C++ library
10 * for processing and rendering 3D data.
11 * Journal of Open Source Software, 6(64), 3255, 2021.
12 * ------------------------------------------------------------------
13 *
14 * Easy3D is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License Version 3
16 * as published by the Free Software Foundation.
17 *
18 * Easy3D is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 ********************************************************************/
26
27#include <easy3d/viewer/viewer.h>
28#include <easy3d/renderer/camera.h>
29#include <easy3d/core/surface_mesh.h>
30#include <easy3d/renderer/drawable_points.h>
31#include <easy3d/renderer/drawable_lines.h>
32#include <easy3d/renderer/renderer.h>
33#include <easy3d/algo/tessellator.h>
34#include <easy3d/util/initializer.h>
35
36
37using namespace easy3d;
38
39
40// This example shows how to triangulate a general polygonal meshes (e.g., meshes
41// with concave faces, self−intersecting faces, and faces with holes) using the
42// tessellator of Easy3D.
43//
44// Note: For general rendering purposes, you can use the tessellator to create a
45// TrianglesDrawable for the model without explicitly triangulating the mesh.
46
47typedef std::vector<vec3> Hole;
48
49// convert the mesh into a triangular mesh using the tessellator
50void triangulate(SurfaceMesh *mesh) {
51 if (!mesh)
52 return;
53
54 mesh->update_face_normals();
55 auto normals = mesh->face_property<vec3>("f:normal");
56 auto holes = mesh->get_face_property<Hole>("f:holes");
57
58 Tessellator tessellator;
59 for (auto f : mesh->faces()) {
60 tessellator.begin_polygon(normals[f]);
61
62 tessellator.set_winding_rule(Tessellator::WINDING_NONZERO);
63 tessellator.begin_contour();
64 for (auto h : mesh->halfedges(f)) {
65 SurfaceMesh::Vertex v = mesh->target(h);
66 tessellator.add_vertex(mesh->position(v), v.idx());
67 }
68 tessellator.end_contour();
69
70 if (holes && holes[f].size() >= 3) { // has a valid hole
71 tessellator.set_winding_rule(Tessellator::WINDING_ODD);
72 tessellator.begin_contour();
73 for (const auto& p : holes[f])
74 tessellator.add_vertex(p);
75 tessellator.end_contour();
76 }
77
78 tessellator.end_polygon();
79 }
80
81 // now the tessellation is done. We can clear the old mesh and
82 // fill it will the new set of triangles
83
84 mesh->clear();
85
86 const auto& triangles = tessellator.elements();
87 if (triangles.empty())
88 return; // in degenerate cases num can be zero
89
90 const auto &vts = tessellator.vertices();
91 for (auto v: vts)
92 mesh->add_vertex(vec3(v->data()));
93
94 for (const auto &t: triangles) {
95 mesh->add_triangle(
96 SurfaceMesh::Vertex(static_cast<int>(t[0])),
97 SurfaceMesh::Vertex(static_cast<int>(t[1])),
98 SurfaceMesh::Vertex(static_cast<int>(t[2]))
99 );
100 }
101}
102
103
104int main(int argc, char **argv) {
105 // initialize Easy3D.
106 initialize();
107
108 // create the default Easy3D viewer.
109 // (a viewer must be created before creating any drawables).
110 Viewer viewer(EXAMPLE_TITLE);
111 viewer.camera()->setUpVector(vec3(0, 1, 0));
112 viewer.camera()->setViewDirection(vec3(0, 0, -1));
113
114 //-------- create a simple mesh with 3 complex faces ---------
115
116 auto mesh = new SurfaceMesh;
117
118 { // face 1: a concave quad
119 auto v0 = mesh->add_vertex(vec3(0, 0, 0));
120 auto v1 = mesh->add_vertex(vec3(800, 0, 0));
121 auto v2 = mesh->add_vertex(vec3(800, 800, 0));
122 auto v3 = mesh->add_vertex(vec3(600, 300, 0));
123 mesh->add_quad(v0, v1, v2, v3);
124 }
125
126 { // face 2: a self-intersecting face representing a star
127 auto vertices = {
128 mesh->add_vertex(vec3(1500, 0, 0)),
129 mesh->add_vertex(vec3(1300, 800, 0)),
130 mesh->add_vertex(vec3(1100, 0, 0)),
131 mesh->add_vertex(vec3(1700, 500, 0)),
132 mesh->add_vertex(vec3(900, 500, 0))
133 };
134 mesh->add_face(vertices);
135 }
136
137 { // face 3: a quad face with a hole
138 auto vertices = {
139 mesh->add_vertex(vec3(1800, 0, 0)),
140 mesh->add_vertex(vec3(2200, 0, 0)),
141 mesh->add_vertex(vec3(2200, 700, 0)),
142 mesh->add_vertex(vec3(1800, 700, 0))
143 };
144 auto f = mesh->add_face(vertices);
145
146 // let's create a hole (also a quad shape) in this face
147 auto holes = mesh->add_face_property<Hole>("f:holes");
148 holes[f] = {
149 vec3(1900, 100, 0),
150 vec3(2100, 100, 0),
151 vec3(2100, 600, 0),
152 vec3(1900, 600, 0)
153 };
154 }
155
156 //-------- triangulate the mesh using the tessellator ---------
157
158 triangulate(mesh);
159
160 // ------------------------------------------------------------
161
162 // add the model to the viewer
163 viewer.add_model(mesh, true);
164
165 // show the vertices
166 mesh->renderer()->get_points_drawable("vertices")->set_visible(true);
167 mesh->renderer()->get_points_drawable("vertices")->set_impostor_type(easy3d::PointsDrawable::SPHERE);
168 mesh->renderer()->get_points_drawable("vertices")->set_point_size(12);
169 // show the edges
170 mesh->renderer()->get_lines_drawable("edges")->set_visible(true);
171 // also show the borders
172 mesh->renderer()->get_lines_drawable("borders")->set_visible(true);
173
174 // run the viewer
175 return viewer.run();
176}
177
int idx() const
Get the underlying index of this handle.
Definition: surface_mesh.h:67
A halfedge data structure for polygonal meshes of 2-manifold.
Definition: surface_mesh.h:52
const vec3 & position(Vertex v) const
position of a vertex (read only)
Definition: surface_mesh.h:1928
FaceProperty< T > get_face_property(const std::string &name) const
Definition: surface_mesh.h:1435
FaceContainer faces() const
returns face container for C++11 range-based for-loops
Definition: surface_mesh.h:1685
void update_face_normals()
compute face normals by calling compute_face_normal(Face) for each face.
Definition: surface_mesh.cpp:1011
Vertex target(Halfedge h) const
returns the vertex the halfedge h points to
Definition: surface_mesh.h:1211
HalfedgeContainer halfedges() const
returns halfedge container for C++11 range-based for-loops
Definition: surface_mesh.h:1649
FaceProperty< T > face_property(const std::string &name, const T t=T())
Definition: surface_mesh.h:1475
Face add_triangle(Vertex v1, Vertex v2, Vertex v3)
Definition: surface_mesh.cpp:491
Vertex add_vertex(const vec3 &p)
add a new vertex with position p
Definition: surface_mesh.h:1034
void clear()
Removes all vertices, edges, faces, and properties (and resets garbage state).
Definition: surface_mesh.cpp:302
Tessellator subdivides concave planar polygons, polygons with holes, or polygons with intersecting ed...
Definition: tessellator.h:56
void begin_polygon(const vec3 &normal)
Begin the tessellation of a complex polygon.
Definition: tessellator.cpp:143
The built-in Easy3D viewer.
Definition: viewer.h:61
Definition: collider.cpp:182
void initialize(bool use_log_file, bool use_setting_file, const std::string &resource_dir)
Initialization of Easy3D.
Definition: initializer.cpp:35
Definition: surface_mesh.h:104