MVE - Multi-View Environment mve-devel
Loading...
Searching...
No Matches
mesh.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015, Simon Fuhrmann
3 * TU Darmstadt - Graphics, Capture and Massively Parallel Computing
4 * All rights reserved.
5 *
6 * This software may be modified and distributed under the terms
7 * of the BSD 3-Clause license. See the LICENSE.txt file for details.
8 */
9
10#include <iostream>
11
12#include "math/defines.h"
13#include "math/functions.h"
14#include "mve/mesh.h"
15
16/*
17 * Whether to use AWPN (angle-weighted pseudo normals)
18 * or AWFN (area-weighted face normals).
19 */
20#define MESH_AWPN_NORMALS 1
21
23
24void
25TriangleMesh::recalc_normals (bool face, bool vertex)
26{
27 if (!face && !vertex)
28 return;
29
30 if (face)
31 {
32 this->face_normals.clear();
33 this->face_normals.reserve(this->faces.size() / 3);
34 }
35
36 if (vertex)
37 {
38 this->vertex_normals.clear();
39 this->vertex_normals.resize(this->vertices.size(), math::Vec3f(0.0f));
40 }
41
42 std::size_t zlfn = 0;
43 std::size_t zlvn = 0;
44
45 for (std::size_t i = 0; i < this->faces.size(); i += 3)
46 {
47 /* Face vertex indices. */
48 std::size_t ia = this->faces[i + 0];
49 std::size_t ib = this->faces[i + 1];
50 std::size_t ic = this->faces[i + 2];
51
52 /* Face vertices. */
53 math::Vec3f const& a = this->vertices[ia];
54 math::Vec3f const& b = this->vertices[ib];
55 math::Vec3f const& c = this->vertices[ic];
56
57 /* Face edges. */
58 math::Vec3f ab = b - a;
59 math::Vec3f bc = c - b;
60 math::Vec3f ca = a - c;
61
62 /* Face normal. */
63 math::Vec3f fn = ab.cross(-ca);
64 float fnl = fn.norm();
65
66 /* Count zero-length face normals. */
67 if (fnl == 0.0f)
68 zlfn += 1;
69
70#if MESH_AWPN_NORMALS
71
72 /*
73 * Calculate angle weighted pseudo normals by weighted
74 * averaging adjacent face normals.
75 */
76
77 /* Normalize face normal. */
78 if (fnl != 0.0f)
79 fn /= fnl;
80
81 /* Add (normalized) face normal. */
82 if (face)
83 this->face_normals.push_back(fn);
84
85 /* Update adjacent vertex normals. */
86 if (fnl != 0.0f && vertex)
87 {
88 float abl = ab.norm();
89 float bcl = bc.norm();
90 float cal = ca.norm();
91
92 /*
93 * Although (a.dot(b) / (alen * blen)) is more efficient,
94 * (a / alen).dot(b / blen) is numerically more stable.
95 */
96 float ratio1 = (ab / abl).dot(-ca / cal);
97 float ratio2 = (-ab / abl).dot(bc / bcl);
98 float ratio3 = (ca / cal).dot(-bc / bcl);
99 float angle1 = std::acos(math::clamp(ratio1, -1.0f, 1.0f));
100 float angle2 = std::acos(math::clamp(ratio2, -1.0f, 1.0f));
101 float angle3 = std::acos(math::clamp(ratio3, -1.0f, 1.0f));
102
103 //float angle1 = std::acos(ab.dot(-ca) / (abl * cal));
104 //float angle2 = std::acos((-ab).dot(bc) / (abl * bcl));
105 //float angle3 = std::acos(ca.dot(-bc) / (cal * bcl));
106
107 this->vertex_normals[ia] += fn * angle1;
108 this->vertex_normals[ib] += fn * angle2;
109 this->vertex_normals[ic] += fn * angle3;
110
111 if (MATH_ISNAN(angle1) || MATH_ISNAN(angle2) || MATH_ISNAN(angle3))
112 {
113 std::cout << "NAN error in " << __FILE__ << ":" << __LINE__
114 << ": " << angle1 << " / " << angle2 << " / " << angle3
115 << " (" << abl << " / " << bcl << " / " << cal << ")"
116 << " [" << ratio1 << " / " << ratio2 << " / " << ratio3
117 << "]" << std::endl;
118 }
119 }
120
121#else /* no MESH_AWPN_NORMALS */
122
123 /*
124 * Calculate simple vertex normals by averaging
125 * area-weighted adjacent face normals.
126 */
127
128 if (face)
129 {
130 this->face_normals.push_back(fnl ? fn / fnl : fn);
131 }
132
133 if (fnl != 0.0f && vertex)
134 {
135 this->vertex_normals[ia] += fn;
136 this->vertex_normals[ib] += fn;
137 this->vertex_normals[ic] += fn;
138 }
139
140#endif /* MESH_AWPN_NORMALS */
141
142 }
143
144 /* Normalize all vertex normals. */
145 if (vertex)
146 {
147 for (std::size_t i = 0; i < this->vertex_normals.size(); ++i)
148 {
149 float vnl = this->vertex_normals[i].norm();
150 if (vnl > 0.0f)
151 this->vertex_normals[i] /= vnl;
152 else
153 zlvn += 1;
154 }
155 }
156
157 if (zlfn || zlvn)
158 std::cout << "Warning: Zero-length normals detected: "
159 << zlfn << " face normals, " << zlvn << " vertex normals"
160 << std::endl;
161}
162
163/* ---------------------------------------------------------------- */
164
165void
166TriangleMesh::ensure_normals (bool face, bool vertex)
167{
168 bool need_face_recalc = (face
169 && this->face_normals.size() != this->faces.size() / 3);
170 bool need_vertex_recalc = (vertex
171 && this->vertex_normals.size() != this->vertices.size());
172 this->recalc_normals(need_face_recalc, need_vertex_recalc);
173}
174
175/* ---------------------------------------------------------------- */
176
177void
178TriangleMesh::delete_vertices (DeleteList const& delete_list)
179{
180 if (delete_list.size() != this->vertices.size())
181 throw std::invalid_argument("Delete list does not match vertex list");
182
183 if (this->has_vertex_normals())
184 math::algo::vector_clean(delete_list, &this->vertex_normals);
185 if (this->has_vertex_colors())
186 math::algo::vector_clean(delete_list, &this->vertex_colors);
187 if (this->has_vertex_confidences())
188 math::algo::vector_clean(delete_list, &this->vertex_confidences);
189 if (this->has_vertex_values())
190 math::algo::vector_clean(delete_list, &this->vertex_values);
191 if (this->has_vertex_texcoords())
192 math::algo::vector_clean(delete_list, &this->vertex_texcoords);
193 math::algo::vector_clean(delete_list, &this->vertices);
194}
195
196/* ---------------------------------------------------------------- */
197
198void
199TriangleMesh::delete_vertices_fix_faces (DeleteList const& dlist)
200{
201 if (dlist.size() != this->vertices.size())
202 throw std::invalid_argument("Delete list does not match vertex list");
203
204 /* Each vertex is shifted to the left. This list tracks the distance. */
205 std::vector<std::size_t> idxshift(this->vertices.size(), 0);
206 std::size_t num_deleted = 0;
207 for (std::size_t i = 0; i < this->vertices.size(); ++i)
208 {
209 idxshift[i] = num_deleted;
210 if (dlist[i] == true)
211 num_deleted += 1;
212 }
213
214 /* Invalidate faces referencing deleted vertices and fix vertex IDs. */
215 for (std::size_t i = 0; i < this->faces.size(); i += 3)
216 {
217 if (dlist[faces[i + 0]] || dlist[faces[i + 1]] || dlist[faces[i + 2]])
218 {
219 faces[i + 0] = 0;
220 faces[i + 1] = 0;
221 faces[i + 2] = 0;
222 }
223 else
224 {
225 faces[i + 0] -= idxshift[faces[i + 0]];
226 faces[i + 1] -= idxshift[faces[i + 1]];
227 faces[i + 2] -= idxshift[faces[i + 2]];
228 }
229 }
230
231 /* Compact vertex and attribute vectors, remove invalid faces. */
232 this->delete_vertices(dlist);
233 this->delete_invalid_faces();
234}
235
236/* ---------------------------------------------------------------- */
237
238namespace
239{
240 bool
241 is_valid_triangle (TriangleMesh::VertexID const* ids)
242 {
243 return ids[0] != ids[1] || ids[0] != ids[2];
244 }
245}
246
247void
248TriangleMesh::delete_invalid_faces (void)
249{
250 /* Valid and invalid iterator. */
251 std::size_t ii = 0;
252 std::size_t vi = this->faces.size();
253 while (vi > ii)
254 {
255 /* Search the next invalid face. */
256 while (ii < this->faces.size() && is_valid_triangle(&this->faces[ii]))
257 ii += 3;
258 /* Search the last valid face. */
259 vi -= 3;
260 while (vi > ii && !is_valid_triangle(&this->faces[vi]))
261 vi -= 3;
262 if (ii >= vi)
263 break;
264 /* Swap valid and invalid face. */
265 std::swap(this->faces[vi + 0], this->faces[ii + 0]);
266 std::swap(this->faces[vi + 1], this->faces[ii + 1]);
267 std::swap(this->faces[vi + 2], this->faces[ii + 2]);
268 }
269 this->faces.resize(ii);
270}
271
272/* ---------------------------------------------------------------- */
273
274std::size_t
275TriangleMesh::get_byte_size (void) const
276{
277 std::size_t s_verts = this->vertices.capacity() * sizeof(math::Vec3f);
278 std::size_t s_faces = this->faces.capacity() * sizeof(VertexID);
279 std::size_t s_vnorm = this->vertex_normals.capacity() * sizeof(math::Vec3f);
280 std::size_t s_fnorm = this->face_normals.capacity() * sizeof(math::Vec3f);
281 std::size_t s_color = this->vertex_colors.capacity() * sizeof(math::Vec3f);
282 return s_verts + s_faces + s_vnorm + s_fnorm + s_color;
283}
284
Vector class for arbitrary dimensions and types.
Definition vector.h:87
Vector< T, N > cross(Vector< T, N > const &other) const
Cross product between this and another vector.
Definition vector.h:549
T norm(void) const
Computes the norm (length) of the vector.
Definition vector.h:434
unsigned int VertexID
Definition mesh.h:32
std::vector< bool > DeleteList
Definition mesh.h:99
#define MATH_ISNAN(x)
Definition defines.h:104
#define MVE_NAMESPACE_BEGIN
Definition defines.h:13
#define MVE_NAMESPACE_END
Definition defines.h:14
void vector_clean(std::vector< bool > const &delete_list, std::vector< T > *vector)
Erases all elements from 'vector' that are marked with 'true' in 'delete_list'.
Definition algo.h:166
T const & clamp(T const &v, T const &min=T(0), T const &max=T(1))
Returns value 'v' clamped to the interval specified by 'min' and 'max'.
Definition functions.h:204
Vector< float, 3 > Vec3f
Definition vector.h:31
void swap(mve::Image< T > &a, mve::Image< T > &b)
Specialization of std::swap for efficient image swapping.
Definition image.h:478