MRPT  2.0.4
CMesh3D.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "opengl-precomp.h" // Precompiled header
11 
12 #include <mrpt/img/color_maps.h>
13 #include <mrpt/opengl/CMesh3D.h>
16 
17 #include <mrpt/opengl/opengl_api.h>
18 
19 using namespace mrpt;
20 using namespace mrpt::opengl;
21 using namespace mrpt::poses;
22 using namespace mrpt::math;
23 using namespace std;
24 
26 
27 CMesh3D::~CMesh3D() = default;
28 
30  unsigned int num_verts, unsigned int num_faces, int* verts_per_face,
31  int* face_verts, float* vert_coords)
32 {
33  // Fill number of vertices for each face
34  m_is_quad.resize(num_faces);
35  for (unsigned int i = 0; i < num_faces; i++)
36  {
37  if (verts_per_face[i] == 3)
38  m_is_quad[i] = false;
39  else if (verts_per_face[i] == 4)
40  m_is_quad[i] = true;
41  else
42  {
44  "Incorrect mesh format. It can only be composed of triangles "
45  "and/or quads");
46  }
47  }
48 
49  // Fill the vertices of each face
50  m_face_verts.resize(num_faces);
51  unsigned int count = 0;
52  for (unsigned int f = 0; f < num_faces; f++)
53  {
54  m_face_verts[f][0] = face_verts[count++];
55  m_face_verts[f][1] = face_verts[count++];
56  m_face_verts[f][2] = face_verts[count++];
57  if (m_is_quad[f])
58  m_face_verts[f][3] = face_verts[count++];
59  else
60  m_face_verts[f][3] = -1; // Meaning it is a triangle
61  }
62 
63  // Fill the 3D coordinates of the vertex
64  m_vertices.resize(num_verts);
65  for (unsigned int i = 0; i < num_verts; i++)
66  {
67  m_vertices[i][0] = vert_coords[3 * i];
68  m_vertices[i][1] = vert_coords[3 * i + 1];
69  m_vertices[i][2] = vert_coords[3 * i + 2];
70  }
71 
72  // Compute the mesh normals (if on)
73  if (m_computeNormals)
74  {
75  m_normals.resize(num_faces);
76 
77  for (unsigned int f = 0; f < num_faces; f++)
78  {
79  const unsigned int v1 = m_face_verts[f][3];
80  const unsigned int v2 = m_face_verts[f][2];
81  const unsigned int v3 = m_face_verts[f][1];
82  const unsigned int v4 = m_face_verts[f][0];
83 
84  if (m_is_quad[f])
85  {
86  const float vec1[3] = {m_vertices[v3][0] - m_vertices[v1][0],
87  m_vertices[v3][1] - m_vertices[v1][1],
88  m_vertices[v3][2] - m_vertices[v1][2]};
89  const float vec2[3] = {m_vertices[v4][0] - m_vertices[v2][0],
90  m_vertices[v4][1] - m_vertices[v2][1],
91  m_vertices[v4][2] - m_vertices[v2][2]};
92  m_normals[f][0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
93  m_normals[f][1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
94  m_normals[f][2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
95  }
96  else
97  {
98  const float vec1[3] = {m_vertices[v2][0] - m_vertices[v1][0],
99  m_vertices[v2][1] - m_vertices[v1][1],
100  m_vertices[v2][2] - m_vertices[v1][2]};
101  const float vec2[3] = {m_vertices[v3][0] - m_vertices[v1][0],
102  m_vertices[v3][1] - m_vertices[v1][1],
103  m_vertices[v3][2] - m_vertices[v1][2]};
104  m_normals[f][0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
105  m_normals[f][1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
106  m_normals[f][2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
107  }
108  m_normals[f] = m_normals[f].unitarize();
109  }
110  }
111 
113 }
114 
116  unsigned int num_verts, unsigned int num_faces,
117  const mrpt::math::CMatrixDynamic<bool>& is_quad,
118  const mrpt::math::CMatrixDynamic<int>& face_verts,
119  const mrpt::math::CMatrixDynamic<float>& vert_coords)
120 {
121  // Fill number of vertices for each face
122  m_is_quad.resize(num_faces);
123  for (unsigned int i = 0; i < num_faces; i++) m_is_quad[i] = is_quad(i, 0);
124 
125  // Fill the vertices of each face
126  m_face_verts.resize(num_faces);
127  for (unsigned int f = 0; f < num_faces; f++)
128  {
129  m_face_verts[f][0] = face_verts(0, f);
130  m_face_verts[f][1] = face_verts(1, f);
131  m_face_verts[f][2] = face_verts(2, f);
132  if (m_is_quad[f])
133  m_face_verts[f][3] = face_verts(3, f);
134  else
135  m_face_verts[f][3] = -1; // Meaning it is a triangle
136  }
137 
138  // Fill the 3D coordinates of the vertex
139  m_vertices.resize(num_verts);
140  for (unsigned int i = 0; i < num_verts; i++)
141  {
142  m_vertices[i][0] = vert_coords(0, i);
143  m_vertices[i][1] = vert_coords(1, i);
144  m_vertices[i][2] = vert_coords(2, i);
145  }
146 
147  // Compute the mesh normals (if on)
148  m_normals.resize(num_faces);
149  if (m_computeNormals)
150  for (unsigned int f = 0; f < num_faces; f++)
151  {
152  const unsigned int v1 = m_face_verts[f][0];
153  const unsigned int v2 = m_face_verts[f][1];
154  const unsigned int v3 = m_face_verts[f][2];
155  const unsigned int v4 = m_face_verts[f][3];
156 
157  if (m_is_quad[f])
158  {
159  const float vec1[3] = {m_vertices[v3][0] - m_vertices[v1][0],
160  m_vertices[v3][1] - m_vertices[v1][1],
161  m_vertices[v3][2] - m_vertices[v1][2]};
162  const float vec2[3] = {m_vertices[v4][0] - m_vertices[v2][0],
163  m_vertices[v4][1] - m_vertices[v2][1],
164  m_vertices[v4][2] - m_vertices[v2][2]};
165  m_normals[f][0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
166  m_normals[f][1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
167  m_normals[f][2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
168  }
169  else
170  {
171  const float vec1[3] = {m_vertices[v2][0] - m_vertices[v1][0],
172  m_vertices[v2][1] - m_vertices[v1][1],
173  m_vertices[v2][2] - m_vertices[v1][2]};
174  const float vec2[3] = {m_vertices[v3][0] - m_vertices[v1][0],
175  m_vertices[v3][1] - m_vertices[v1][1],
176  m_vertices[v3][2] - m_vertices[v1][2]};
177  m_normals[f][0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
178  m_normals[f][1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
179  m_normals[f][2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
180  }
181  }
182 
184 }
185 
186 void CMesh3D::render(const RenderContext& rc) const
187 {
188  switch (rc.shader_id)
189  {
191  if (m_showFaces) CRenderizableShaderTriangles::render(rc);
192  break;
194  if (m_showEdges) CRenderizableShaderWireFrame::render(rc);
195  break;
197  if (m_showVertices) CRenderizableShaderPoints::render(rc);
198  break;
199  };
200 }
202 {
206 }
207 
209 {
212  vbd.clear();
213 
214  for (size_t f = 0; f < m_face_verts.size(); f++)
215  {
216  const unsigned char num_vert = 3 + m_is_quad[f];
217  for (int i = 0; i < num_vert - 1; i++)
218  {
219  const unsigned int v_0 = m_face_verts[f][i];
220  const unsigned int v_1 = m_face_verts[f][i + 1];
221 
222  vbd.emplace_back(m_vertices[v_0]);
223  vbd.emplace_back(m_vertices[v_1]);
224  }
225 
226  // The last vertex of the face needs to be connected to the first as
227  // well
228  const int v_0 = m_face_verts[f][num_vert - 1];
229  const int v_1 = m_face_verts[f][0];
230 
231  vbd.emplace_back(m_vertices[v_0]);
232  vbd.emplace_back(m_vertices[v_1]);
233  }
234 
235  cbd.assign(vbd.size(), edge_color.asTColor());
236 }
237 
239 {
241  tris.clear();
242 
243  for (size_t f = 0; f < m_is_quad.size(); f++)
244  {
245  // Assign normals to faces (if on)
246  const auto& normal = m_normals[f];
247 
248  tris.emplace_back(
249  m_vertices[m_face_verts[f][0]], m_vertices[m_face_verts[f][1]],
250  m_vertices[m_face_verts[f][2]], normal, normal, normal);
251  if (m_is_quad[f])
252  {
253  tris.emplace_back(
254  m_vertices[m_face_verts[f][0]], m_vertices[m_face_verts[f][2]],
255  m_vertices[m_face_verts[f][3]], normal, normal, normal);
256  }
257  }
258 
259  for (auto& t : tris) t.setColor(face_color);
260 }
262 {
265 
266  vbd = m_vertices;
267  cbd.assign(m_vertices.size(), vert_color.asTColor());
268 }
269 
270 uint8_t CMesh3D::serializeGetVersion() const { return 0; }
272 {
273  writeToStreamRender(out);
274  out << m_showEdges << m_showFaces << m_showVertices << m_computeNormals;
275  out << m_is_quad << m_vertices << m_normals;
276  out.WriteAs<uint32_t>(m_face_verts.size());
277  if (!m_face_verts.empty())
278  out.WriteBufferFixEndianness<uint32_t>(
279  m_face_verts[0].data(),
280  m_face_verts.size() * m_face_verts[0].size());
281 }
282 
284 {
285  readFromStreamRender(in);
286  in >> m_showEdges >> m_showFaces >> m_showVertices >> m_computeNormals;
287  in >> m_is_quad >> m_vertices >> m_normals;
288  const auto N = in.ReadAs<uint32_t>();
289  m_face_verts.resize(N);
290  if (!m_face_verts.empty())
291  in.ReadBufferFixEndianness<uint32_t>(
292  m_face_verts[0].data(),
293  m_face_verts.size() * m_face_verts[0].size());
294 }
295 
298 {
299  if (m_vertices.empty())
300  {
301  bb_max = TPoint3D(0, 0, 0);
302  bb_min = TPoint3D(0, 0, 0);
303  }
304  else
305  {
306  bb_min.x = std::numeric_limits<double>::max();
307  bb_min.y = std::numeric_limits<double>::max();
308  bb_min.z = std::numeric_limits<double>::max();
309  bb_max.x = -std::numeric_limits<double>::max();
310  bb_max.y = -std::numeric_limits<double>::max();
311  bb_max.z = -std::numeric_limits<double>::max();
312 
313  for (size_t i = 0; i < m_vertices.size(); i++)
314  {
315  // Max
316  mrpt::keep_max(bb_max.x, m_vertices[i][0]);
317  mrpt::keep_max(bb_max.y, m_vertices[i][1]);
318  mrpt::keep_max(bb_max.z, m_vertices[i][2]);
319 
320  // Min
321  mrpt::keep_min(bb_min.x, m_vertices[i][0]);
322  mrpt::keep_min(bb_min.y, m_vertices[i][1]);
323  mrpt::keep_min(bb_min.z, m_vertices[i][2]);
324  }
325  }
326 
327  // Convert to coordinates of my parent:
328  m_pose.composePoint(bb_min, bb_min);
329  m_pose.composePoint(bb_max, bb_max);
330 }
void keep_min(T &var, const K test_val)
If the second argument is below the first one, set the first argument to this lower value...
std::vector< mrpt::math::TPoint3Df > m_vertex_buffer_data
void resize(size_t row, size_t col)
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive.
Definition: CMesh3D.cpp:271
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
void serializeFrom(mrpt::serialization::CArchive &in, uint8_t serial_version) override
Pure virtual method for reading (deserializing) from an abstract archive.
Definition: CMesh3D.cpp:283
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
To be added to all CSerializable-classes implementation files.
void notifyChange() const
Call to enable calling renderUpdateBuffers() before the next render() rendering iteration.
The base class of 3D objects that can be directly rendered through OpenGL.
Definition: CRenderizable.h:48
STL namespace.
A 3D mesh composed of Triangles and/or Quads.
Definition: CMesh3D.h:35
void renderUpdateBuffers() const override
Called whenever m_outdatedBuffers is true: used to re-generate OpenGL vertex buffers, etc.
void render(const RenderContext &rc) const override
Implements the rendering of 3D objects in each class derived from CRenderizable.
Definition: CMesh3D.cpp:186
void renderUpdateBuffers() const override
Called whenever m_outdatedBuffers is true: used to re-generate OpenGL vertex buffers, etc.
Context for calls to render()
std::vector< mrpt::math::TPoint3Df > m_vertex_buffer_data
std::vector< mrpt::img::TColor > m_color_buffer_data
This base provides a set of functions for maths stuff.
void renderUpdateBuffers() const override
Called whenever m_outdatedBuffers is true: used to re-generate OpenGL vertex buffers, etc.
Definition: CMesh3D.cpp:201
uint8_t serializeGetVersion() const override
Must return the current versioning number of the object.
Definition: CMesh3D.cpp:270
STORED_TYPE ReadAs()
De-serialize a variable and returns it by value.
Definition: CArchive.h:155
static constexpr shader_id_t WIREFRAME
TPoint3D_< double > TPoint3D
Lightweight 3D point.
Definition: TPoint3D.h:268
void loadMesh(unsigned int num_verts, unsigned int num_faces, int *verts_per_face, int *face_verts, float *vert_coords)
Load a 3D mesh.
Definition: CMesh3D.cpp:29
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
static constexpr shader_id_t TRIANGLES
void keep_max(T &var, const K test_val)
If the second argument is above the first one, set the first argument to this higher value...
void onUpdateBuffers_Triangles() override
Must be implemented in derived classes to update the geometric entities to be drawn in "m_*_buffer" f...
Definition: CMesh3D.cpp:238
std::vector< mrpt::img::TColor > m_color_buffer_data
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:54
std::vector< mrpt::opengl::TTriangle > m_triangles
List of triangles.
virtual ~CMesh3D() override
mrpt::vision::TStereoCalibResults out
void onUpdateBuffers_Points() override
Must be implemented in derived classes to update the geometric entities to be drawn in "m_*_buffer" f...
Definition: CMesh3D.cpp:261
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:13
const auto bb_max
void render(const RenderContext &rc) const override
Implements the rendering of 3D objects in each class derived from CRenderizable.
const auto bb_min
void onUpdateBuffers_Wireframe() override
Must be implemented in derived classes to update the geometric entities to be drawn in "m_*_buffer" f...
Definition: CMesh3D.cpp:208
size_t ReadBufferFixEndianness(T *ptr, size_t ElementCount)
Reads a sequence of elemental datatypes, taking care of reordering their bytes from the MRPT stream s...
Definition: CArchive.h:94
This template class provides the basic functionality for a general 2D any-size, resizable container o...
void render(const RenderContext &rc) const override
Implements the rendering of 3D objects in each class derived from CRenderizable.
void getBoundingBox(mrpt::math::TPoint3D &bb_min, mrpt::math::TPoint3D &bb_max) const override
Evaluates the bounding box of this object (including possible children) in the coordinate frame of th...
Definition: CMesh3D.cpp:296
static constexpr shader_id_t POINTS
void render(const RenderContext &rc) const override
Implements the rendering of 3D objects in each class derived from CRenderizable.
void renderUpdateBuffers() const override
Called whenever m_outdatedBuffers is true: used to re-generate OpenGL vertex buffers, etc.



Page generated by Doxygen 1.8.14 for MRPT 2.0.4 Git: 7ea9b7e81 Mon May 25 11:43:10 2020 +0200 at lun may 25 11:45:15 CEST 2020