Main MRPT website > C++ reference for MRPT 1.9.9
CMesh3D.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "opengl-precomp.h" // Precompiled header
11 
12 #include <mrpt/opengl/CMesh3D.h>
13 #include <mrpt/utils/color_maps.h>
14 #include <mrpt/utils/CStream.h>
15 
16 #include "opengl_internals.h"
17 
18 using namespace mrpt;
19 using namespace mrpt::opengl;
20 using namespace mrpt::utils;
21 using namespace mrpt::poses;
22 using namespace mrpt::math;
23 using namespace std;
24 
26 
28  bool enableTransparency, bool antiAliasing, bool enableShowEdges,
29  bool enableShowFaces, bool enableShowVertices)
30  : m_enableTransparency(enableTransparency),
31  m_antiAliasing(antiAliasing),
32  m_showEdges(enableShowEdges),
33  m_showFaces(enableShowFaces),
34  m_showVertices(enableShowVertices),
35  m_computeNormals(true),
36  m_lineWidth(2.f),
37  m_pointSize(6.f),
38  m_colorMap(mrpt::utils::cmHOT)
39 {
40  m_color.R = 1.f;
41  m_color.G = 0.f;
42  m_color.B = 0.f;
43  m_color.A = 1.f;
44  edge_color[0] = 0.9f;
45  edge_color[1] = 0.9f;
46  edge_color[2] = 0.9f;
47  edge_color[3] = 1.f;
48  face_color[0] = 0.7f;
49  face_color[1] = 0.7f;
50  face_color[2] = 0.8f;
51  face_color[3] = 1.f;
52  vert_color[0] = 0.3f;
53  vert_color[1] = 0.3f;
54  vert_color[2] = 0.3f;
55  vert_color[3] = 1.f;
56  m_num_faces = 0;
57  m_num_verts = 0;
58 }
59 
62  unsigned int num_verts, unsigned int num_faces, int* verts_per_face,
63  int* face_verts, float* vert_coords)
64 {
65  m_num_verts = num_verts;
66  m_num_faces = num_faces;
67 
68  // Fill number of vertices for each face
69  m_is_quad = new bool[num_faces];
70  for (unsigned int i = 0; i < num_faces; i++)
71  {
72  if (verts_per_face[i] == 3)
73  m_is_quad[i] = false;
74  else if (verts_per_face[i] == 4)
75  m_is_quad[i] = true;
76  else
77  {
78  printf(
79  "\n Incorrect mesh format. It can only be composed of "
80  "triangles and/or quads.");
81  return;
82  }
83  }
84 
85  // Fill the vertices of each face
86  m_face_verts = new f_verts[num_faces];
87  unsigned int count = 0;
88  for (unsigned int f = 0; f < num_faces; f++)
89  {
90  m_face_verts[f][0] = face_verts[count++];
91  m_face_verts[f][1] = face_verts[count++];
92  m_face_verts[f][2] = face_verts[count++];
93  if (m_is_quad[f])
94  m_face_verts[f][3] = face_verts[count++];
95  else
96  m_face_verts[f][3] = -1; // Meaning it is a triangle
97  }
98 
99  // Fill the 3D coordinates of the vertex
100  m_vert_coords = new coord3D[num_verts];
101  for (unsigned int i = 0; i < num_verts; i++)
102  {
103  m_vert_coords[i][0] = vert_coords[3 * i];
104  m_vert_coords[i][1] = vert_coords[3 * i + 1];
105  m_vert_coords[i][2] = vert_coords[3 * i + 2];
106  }
107 
108  // Compute the mesh normals (if on)
109  if (m_computeNormals)
110  {
111  m_normals = new coord3D[num_faces];
112 
113  for (unsigned int f = 0; f < num_faces; f++)
114  {
115  const unsigned int v1 = m_face_verts[f][0];
116  const unsigned int v2 = m_face_verts[f][1];
117  const unsigned int v3 = m_face_verts[f][2];
118  const unsigned int v4 = m_face_verts[f][3];
119 
120  if (m_is_quad[f])
121  {
122  const float vec1[3] = {
123  m_vert_coords[v3][0] - m_vert_coords[v1][0],
124  m_vert_coords[v3][1] - m_vert_coords[v1][1],
125  m_vert_coords[v3][2] - m_vert_coords[v1][2]};
126  const float vec2[3] = {
127  m_vert_coords[v4][0] - m_vert_coords[v2][0],
128  m_vert_coords[v4][1] - m_vert_coords[v2][1],
129  m_vert_coords[v4][2] - m_vert_coords[v2][2]};
130  m_normals[f][0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
131  m_normals[f][1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
132  m_normals[f][2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
133  }
134  else
135  {
136  const float vec1[3] = {
137  m_vert_coords[v2][0] - m_vert_coords[v1][0],
138  m_vert_coords[v2][1] - m_vert_coords[v1][1],
139  m_vert_coords[v2][2] - m_vert_coords[v1][2]};
140  const float vec2[3] = {
141  m_vert_coords[v3][0] - m_vert_coords[v1][0],
142  m_vert_coords[v3][1] - m_vert_coords[v1][1],
143  m_vert_coords[v3][2] - m_vert_coords[v1][2]};
144  m_normals[f][0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
145  m_normals[f][1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
146  m_normals[f][2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
147  }
148  }
149  }
150 
152 }
153 
155  unsigned int num_verts, unsigned int num_faces,
156  const Array<bool, 1, Dynamic>& is_quad,
157  const Array<int, 4, Dynamic>& face_verts,
158  const Array<float, 3, Dynamic>& vert_coords)
159 {
160  m_num_verts = num_verts;
161  m_num_faces = num_faces;
162 
163  // Fill number of vertices for each face
164  m_is_quad = new bool[num_faces];
165  for (unsigned int i = 0; i < num_faces; i++) m_is_quad[i] = is_quad(i);
166 
167  // Fill the vertices of each face
168  m_face_verts = new f_verts[num_faces];
169  for (unsigned int f = 0; f < num_faces; f++)
170  {
171  m_face_verts[f][0] = face_verts(0, f);
172  m_face_verts[f][1] = face_verts(1, f);
173  m_face_verts[f][2] = face_verts(2, f);
174  if (m_is_quad[f])
175  m_face_verts[f][3] = face_verts(3, f);
176  else
177  m_face_verts[f][3] = -1; // Meaning it is a triangle
178  }
179 
180  // Fill the 3D coordinates of the vertex
181  m_vert_coords = new coord3D[num_verts];
182  for (unsigned int i = 0; i < num_verts; i++)
183  {
184  m_vert_coords[i][0] = vert_coords(0, i);
185  m_vert_coords[i][1] = vert_coords(1, i);
186  m_vert_coords[i][2] = vert_coords(2, i);
187  }
188 
189  // Compute the mesh normals (if on)
190  m_normals = new coord3D[num_faces];
191  if (m_computeNormals)
192  for (unsigned int f = 0; f < num_faces; f++)
193  {
194  const unsigned int v1 = m_face_verts[f][0];
195  const unsigned int v2 = m_face_verts[f][1];
196  const unsigned int v3 = m_face_verts[f][2];
197  const unsigned int v4 = m_face_verts[f][3];
198 
199  if (m_is_quad[f])
200  {
201  const float vec1[3] = {
202  m_vert_coords[v3][0] - m_vert_coords[v1][0],
203  m_vert_coords[v3][1] - m_vert_coords[v1][1],
204  m_vert_coords[v3][2] - m_vert_coords[v1][2]};
205  const float vec2[3] = {
206  m_vert_coords[v4][0] - m_vert_coords[v2][0],
207  m_vert_coords[v4][1] - m_vert_coords[v2][1],
208  m_vert_coords[v4][2] - m_vert_coords[v2][2]};
209  m_normals[f][0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
210  m_normals[f][1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
211  m_normals[f][2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
212  }
213  else
214  {
215  const float vec1[3] = {
216  m_vert_coords[v2][0] - m_vert_coords[v1][0],
217  m_vert_coords[v2][1] - m_vert_coords[v1][1],
218  m_vert_coords[v2][2] - m_vert_coords[v1][2]};
219  const float vec2[3] = {
220  m_vert_coords[v3][0] - m_vert_coords[v1][0],
221  m_vert_coords[v3][1] - m_vert_coords[v1][1],
222  m_vert_coords[v3][2] - m_vert_coords[v1][2]};
223  m_normals[f][0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
224  m_normals[f][1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
225  m_normals[f][2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
226  }
227  }
228 
230 }
231 
232 /*---------------------------------------------------------------
233  render
234  ---------------------------------------------------------------*/
235 void CMesh3D::render_dl() const
236 {
237 #if MRPT_HAS_OPENGL_GLUT
238 
239  if (m_enableTransparency || m_antiAliasing)
240  {
243  }
244  else
245  {
248  }
249 
250  glEnable(GL_NORMALIZE); // So the GPU normalizes the normals instead of
251  // doing it in the CPU
254 
255  if (m_num_verts == 0) return;
256 
257  //---------------------------------------------------------------------------------------------------------
258  // Rendering - Test whether changing the rendering mode
259  // continuously
260  // is
261  // very slow (or not)
262  //---------------------------------------------------------------------------------------------------------
263 
264  // Render the faces
265  if (m_showFaces)
266  {
267  glColor4f(face_color[0], face_color[1], face_color[2], face_color[3]);
268 
269  for (unsigned int f = 0; f < m_num_faces; f++)
270  {
271  // Assign normals to faces (if on)
272  if (m_computeNormals)
273  glNormal3f(m_normals[f][0], m_normals[f][1], m_normals[f][2]);
274 
275  // Render Quads
276  if (m_is_quad[f])
277  {
278  glBegin(GL_QUADS);
279  for (int i = 0; i < 4; i++)
280  {
281  const unsigned int vert_ind = m_face_verts[f][i];
282  glVertex3f(
283  m_vert_coords[vert_ind][0], m_vert_coords[vert_ind][1],
284  m_vert_coords[vert_ind][2]);
285  }
286  glEnd();
287  }
288  // Render Triangles
289  else
290  {
292  for (int i = 0; i < 3; i++)
293  {
294  const unsigned int vert_ind = m_face_verts[f][i];
295  glVertex3f(
296  m_vert_coords[vert_ind][0], m_vert_coords[vert_ind][1],
297  m_vert_coords[vert_ind][2]);
298  }
299  glEnd();
300  }
301  }
302  }
303 
304  // Render the edges - They are rendered twice, which is redundant but simple
305  if (m_showEdges)
306  {
307  glColor4f(edge_color[0], edge_color[1], edge_color[2], edge_color[3]);
308  glDisable(GL_LIGHTING); //??
309  glLineWidth(m_lineWidth);
311  glBegin(GL_LINES);
312  for (unsigned int f = 0; f < m_num_faces; f++)
313  {
314  const unsigned char num_vert = 3 + m_is_quad[f];
315  for (int i = 0; i < num_vert - 1; i++)
316  {
317  const unsigned int v_0 = m_face_verts[f][i];
318  const unsigned int v_1 = m_face_verts[f][i + 1];
319 
320  glVertex3f(
321  m_vert_coords[v_0][0], m_vert_coords[v_0][1],
322  m_vert_coords[v_0][2]);
323  glVertex3f(
324  m_vert_coords[v_1][0], m_vert_coords[v_1][1],
325  m_vert_coords[v_1][2]);
326  }
327 
328  // The last vertex of the face needs to be connected to the first as
329  // well
330  const int v_0 = m_face_verts[f][num_vert - 1];
331  const int v_1 = m_face_verts[f][0];
332 
333  glVertex3f(
334  m_vert_coords[v_0][0], m_vert_coords[v_0][1],
335  m_vert_coords[v_0][2]);
336  glVertex3f(
337  m_vert_coords[v_1][0], m_vert_coords[v_1][1],
338  m_vert_coords[v_1][2]);
339  }
340  glEnd();
343  }
344 
345  // Render the vertices
346  if (m_showVertices)
347  {
348  glColor4f(vert_color[0], vert_color[1], vert_color[2], vert_color[3]);
350  glPointSize(m_pointSize);
353  for (unsigned int v = 0; v < m_num_verts; v++)
354  glVertex3f(
355  m_vert_coords[v][0], m_vert_coords[v][1], m_vert_coords[v][2]);
356 
357  glEnd();
360  }
361 
364 
365 #endif
366 }
367 
368 /*---------------------------------------------------------------
369  Implements the writing to a CStream capability of
370  CSerializable objects
371  ---------------------------------------------------------------*/
372 void CMesh3D::writeToStream(mrpt::utils::CStream& out, int* version) const
373 {
374  //********** To do **********
375  THROW_EXCEPTION("not implemented yet!")
376 
377  // if (version)
378  // *version = 0;
379  // else
380  //{
381  // writeToStreamRender(out);
382 
383  // // Version 0:
384  // out << m_enableTransparency;
385  // out << m_showEdges;
386  // out << m_showFaces;
387  // out << m_showVertices;
388  // out << m_computeNormals;
389  // out << m_num_verts;
390  // out << m_num_faces;
391 
392  // bool *m_is_quad;
393  // f_verts *m_face_verts;
394  // coord3D *m_vert_coords;
395  // coord3D *m_normals;
396  //}
397 }
398 
399 /*---------------------------------------------------------------
400  Implements the reading from a CStream capability of
401  CSerializable objects
402  ---------------------------------------------------------------*/
404 {
405  //********** To do ************
406 
407  // switch(version)
408  //{
409  // case 0:
410  // {
411  // readFromStreamRender(in);
412 
413  // in >> m_enableTransparency;
414  // in >> m_showEdges;
415  // in >> m_showFaces;
416  // in >> m_showVertices;
417  // in >> m_computeNormals;
418  // in >> m_num_verts;
419  // in >> m_num_faces;
420 
421  // bool *m_is_quad;
422  // f_verts *m_face_verts;
423  // coord3D *m_vert_coords;
424  // coord3D *m_normals;
425  // }
426  // break;
427  // default:
428  // MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(version)
429 
430  //};
431  // CRenderizableDisplayList::notifyChange();
432 }
433 
435  mrpt::math::TPoint3D& bb_min, mrpt::math::TPoint3D& bb_max) const
436 {
437  // Extreme initialization
438  bb_min.x = 10000.f;
439  bb_min.y = 10000.f;
440  bb_min.z = 10000.f;
441  bb_max.x = -10000.f;
442  bb_max.y = -10000.f;
443  bb_max.z = -10000.f;
444 
445  if (m_num_verts == 0)
446  printf(
447  "\n The mesh is empty and has no size. The returned information "
448  "has no meaning.");
449  else
450  {
451  for (unsigned int i = 0; i < m_num_verts; i++)
452  {
453  // Max
454  if (m_vert_coords[i][0] > bb_max.x) bb_max.x = m_vert_coords[i][0];
455  if (m_vert_coords[i][1] > bb_max.y) bb_max.y = m_vert_coords[i][1];
456  if (m_vert_coords[i][2] > bb_max.z) bb_max.z = m_vert_coords[i][2];
457 
458  // Min
459  if (m_vert_coords[i][0] < bb_min.x) bb_min.x = m_vert_coords[i][0];
460  if (m_vert_coords[i][1] < bb_min.y) bb_min.y = m_vert_coords[i][1];
461  if (m_vert_coords[i][2] < bb_min.z) bb_min.z = m_vert_coords[i][2];
462  }
463  }
464 
465  // Convert to coordinates of my parent:
466  m_pose.composePoint(bb_min, bb_min);
467  m_pose.composePoint(bb_max, bb_max);
468 }
469 
470 void CMesh3D::setEdgeColor(float r, float g, float b, float a)
471 {
472  edge_color[0] = r;
473  edge_color[1] = g;
474  edge_color[2] = b;
475  edge_color[3] = a;
476 }
477 
478 void CMesh3D::setFaceColor(float r, float g, float b, float a)
479 {
480  face_color[0] = r;
481  face_color[1] = g;
482  face_color[2] = b;
483  face_color[3] = a;
484 }
485 
486 void CMesh3D::setVertColor(float r, float g, float b, float a)
487 {
488  vert_color[0] = r;
489  vert_color[1] = g;
490  vert_color[2] = b;
491  vert_color[3] = a;
492 }
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
A 3D mesh composed of Triangles and/or Quads.
Definition: CMesh3D.h:39
virtual ~CMesh3D()
Private, virtual destructor: only can be deleted from smart pointers
Definition: CMesh3D.cpp:60
void setFaceColor(float r, float g, float b, float a=1.f)
Definition: CMesh3D.cpp:478
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:434
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:61
void setEdgeColor(float r, float g, float b, float a=1.f)
Definition: CMesh3D.cpp:470
void readFromStream(mrpt::utils::CStream &in, int version) override
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
Definition: CMesh3D.cpp:403
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
Definition: CMesh3D.cpp:372
void render_dl() const override
Render.
Definition: CMesh3D.cpp:235
void setVertColor(float r, float g, float b, float a=1.f)
Definition: CMesh3D.cpp:486
A renderizable object suitable for rendering with OpenGL's display lists.
EIGEN_STRONG_INLINE void notifyChange() const
Must be called to notify that the object has changed (so, the display list must be updated)
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:42
GLAPI void GLAPIENTRY glEnable(GLenum cap)
#define GL_QUADS
Definition: glew.h:279
#define GL_DEPTH_TEST
Definition: glew.h:401
#define GL_SRC_ALPHA
Definition: glew.h:286
#define GL_LINES
Definition: glew.h:273
#define GL_NORMALIZE
Definition: glew.h:416
#define GL_SMOOTH
Definition: glew.h:635
#define GL_POINT_SMOOTH
Definition: glew.h:363
#define GL_TRIANGLES
Definition: glew.h:276
GLAPI void GLAPIENTRY glPointSize(GLfloat size)
GLAPI void GLAPIENTRY glLineWidth(GLfloat width)
#define GL_POINTS
Definition: glew.h:272
GLAPI void GLAPIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)
GLAPI void GLAPIENTRY glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz)
GLAPI void GLAPIENTRY glBegin(GLenum mode)
GLAPI void GLAPIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z)
#define GL_COLOR_MATERIAL
Definition: glew.h:392
#define GL_BLEND
Definition: glew.h:432
#define GL_ONE_MINUS_SRC_ALPHA
Definition: glew.h:287
GLAPI void GLAPIENTRY glEnd(void)
GLAPI void GLAPIENTRY glDisable(GLenum cap)
GLAPI void GLAPIENTRY glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
GLAPI void GLAPIENTRY glShadeModel(GLenum mode)
#define GL_LINE_SMOOTH
Definition: glew.h:367
#define GL_LIGHTING
Definition: glew.h:385
GLfloat GLfloat v1
Definition: glext.h:4105
const GLdouble * v
Definition: glext.h:3678
GLuint GLuint GLsizei count
Definition: glext.h:3528
GLubyte GLubyte b
Definition: glext.h:6279
GLuint in
Definition: glext.h:7274
GLfloat GLfloat GLfloat v2
Definition: glext.h:4107
GLubyte g
Definition: glext.h:6279
GLdouble GLdouble GLdouble r
Definition: glext.h:3705
GLubyte GLubyte GLubyte a
Definition: glext.h:6279
GLfloat GLfloat GLfloat GLfloat v3
Definition: glext.h:4109
@ cmHOT
[New in MRPT 1.5.0]
Definition: color_maps.h:36
#define THROW_EXCEPTION(msg)
Definition: mrpt_macros.h:111
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:20
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:16
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:18
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
Lightweight 3D point.
double x
X,Y,Z coordinates.



Page generated by Doxygen 1.9.1 for MRPT 1.9.9 Git: 63ea9d1f1 Thu Nov 23 00:06:53 2017 +0100 at mar 26 may 2026 12:19:29 CEST