moveit2
The MoveIt Motion Planning Framework for ROS 2.
gl_renderer.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Suat Gedikli */
36 
37 #include <GL/glew.h>
38 #ifdef __APPLE__
39 #include <OpenGL/glu.h>
40 #else
41 #include <GL/glu.h>
42 #include <GL/glut.h>
43 #endif
44 #include <GL/freeglut.h>
46 #include <sstream>
47 #include <fstream>
48 #include <stdexcept>
49 #include <vector>
50 #include <thread>
51 #include <rclcpp/logger.hpp>
52 #include <rclcpp/logging.hpp>
53 
54 using namespace std;
55 
56 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit.ros.perception.gl_renderer");
57 
58 mesh_filter::GLRenderer::GLRenderer(unsigned width, unsigned height, float near, float far)
59  : width_(width)
60  , height_(height)
61  , fbo_id_(0)
62  , rbo_id_(0)
63  , rgb_id_(0)
64  , depth_id_(0)
65  , program_(0)
66  , near_(near)
67  , far_(far)
68  , fx_(width >> 1) // 90 degree wide angle
69  , fy_(fx_)
70  , cx_(width >> 1)
71  , cy_(height >> 1)
72 {
73  createGLContext();
74  initFrameBuffers();
75 }
76 
78 {
79  glDeleteProgram(program_);
80  deleteFrameBuffers();
81  deleteGLContext();
82 }
83 
84 void mesh_filter::GLRenderer::setBufferSize(unsigned width, unsigned height)
85 {
86  if (width_ != width || height_ != height)
87  {
88  width_ = width;
89  height_ = height;
90  deleteFrameBuffers();
91  initFrameBuffers();
92  }
93 }
94 
95 void mesh_filter::GLRenderer::setClippingRange(float near, float far)
96 {
97  if (near_ <= 0)
98  throw runtime_error("near clipping plane distance needs to be larger than 0");
99  if (far_ <= near_)
100  throw runtime_error("far clipping plane needs to be larger than near clipping plane distance");
101  near_ = near;
102  far_ = far;
103 }
104 
105 void mesh_filter::GLRenderer::setCameraParameters(float fx, float fy, float cx, float cy)
106 {
107  fx_ = fx;
108  fy_ = fy;
109  cx_ = cx;
110  cy_ = cy;
111 }
112 
113 void mesh_filter::GLRenderer::setCameraParameters() const
114 {
115  float left = near_ * -cx_ / fx_;
116  float right = near_ * (width_ - cx_) / fx_;
117  float top = near_ * cy_ / fy_;
118  float bottom = near_ * (cy_ - height_) / fy_;
119 
120  glMatrixMode(GL_PROJECTION);
121  glLoadIdentity();
122  glFrustum(left, right, bottom, top, near_, far_);
123 
124  glMatrixMode(GL_MODELVIEW);
125  glLoadIdentity();
126  gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0);
127 }
128 
129 void mesh_filter::GLRenderer::initFrameBuffers()
130 {
131  glGenTextures(1, &rgb_id_);
132  glBindTexture(GL_TEXTURE_2D, rgb_id_);
133  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
134  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
135  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
136  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
137  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
138  glBindTexture(GL_TEXTURE_2D, 0);
139 
140  glGenTextures(1, &depth_id_);
141  glBindTexture(GL_TEXTURE_2D, depth_id_);
142  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
143  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
144  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
145  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
146  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
147  glBindTexture(GL_TEXTURE_2D, 0);
148 
149  glGenFramebuffers(1, &fbo_id_);
150  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
151  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgb_id_, 0);
152 
153  glGenRenderbuffers(1, &rbo_id_);
154  glBindRenderbuffer(GL_RENDERBUFFER, rbo_id_);
155  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_);
156  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_id_);
157  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id_, 0);
158  glBindRenderbuffer(GL_RENDERBUFFER, 0);
159 
160  GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
161  glDrawBuffers(2, draw_buffers);
162 
163  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
164 
165  if (status != GL_FRAMEBUFFER_COMPLETE) // If the frame buffer does not report back as complete
166  throw runtime_error("Couldn't create frame buffer");
167 
168  glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer
169 }
170 
171 void mesh_filter::GLRenderer::deleteFrameBuffers()
172 {
173  if (rbo_id_)
174  glDeleteRenderbuffers(1, &rbo_id_);
175  if (fbo_id_)
176  glDeleteFramebuffers(1, &fbo_id_);
177  if (depth_id_)
178  glDeleteTextures(1, &depth_id_);
179  if (rgb_id_)
180  glDeleteTextures(1, &rgb_id_);
181 
182  rbo_id_ = fbo_id_ = depth_id_ = rgb_id_ = 0;
183 }
184 
186 {
187  glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT | GL_PIXEL_MODE_BIT);
188  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
189  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
190  glViewport(0, 0, width_, height_);
191  glUseProgram(program_);
192  setCameraParameters();
193 }
194 
195 void mesh_filter::GLRenderer::callList(GLuint list) const
196 {
197  begin();
198  glCallList(list);
199  end();
200 }
201 
203 {
204  glFlush();
205  glPopAttrib();
206  glBindFramebuffer(GL_FRAMEBUFFER, 0);
207 }
208 
209 void mesh_filter::GLRenderer::getColorBuffer(unsigned char* buffer) const
210 {
211  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
212  glBindTexture(GL_TEXTURE_2D, rgb_id_);
213  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
214  glBindFramebuffer(GL_FRAMEBUFFER, 0);
215 }
216 
218 {
219  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
220  glBindTexture(GL_TEXTURE_2D, depth_id_);
221  glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, buffer);
222  glBindFramebuffer(GL_FRAMEBUFFER, 0);
223 }
224 
225 GLuint mesh_filter::GLRenderer::setShadersFromFile(const string& vertex_filename, const string& fragment_filename)
226 {
227  if (program_)
228  glDeleteProgram(program_);
229 
230  string vertex_source, fragment_source;
231  readShaderCodeFromFile(vertex_filename, vertex_source);
232  readShaderCodeFromFile(fragment_filename, fragment_source);
233 
234  program_ = loadShaders(vertex_source, fragment_source);
235  return program_;
236 }
237 
238 GLuint mesh_filter::GLRenderer::setShadersFromString(const string& vertex_source, const string& fragment_source)
239 {
240  program_ = loadShaders(vertex_source, fragment_source);
241  return program_;
242 }
243 
245 {
246  return program_;
247 }
248 
250 {
251  return near_;
252 }
253 
255 {
256  return far_;
257 }
258 
259 GLuint mesh_filter::GLRenderer::createShader(GLuint shaderType, const string& ShaderCode) const
260 {
261  GLuint shader_id = glCreateShader(shaderType);
262 
263  // Compile Shader
264  char const* source_pointer = ShaderCode.c_str();
265  glShaderSource(shader_id, 1, &source_pointer, nullptr);
266  glCompileShader(shader_id);
267 
268  // Check Shader
269  GLint result = GL_FALSE;
270  glGetShaderiv(shader_id, GL_COMPILE_STATUS, &result);
271  if (result != GL_TRUE)
272  {
273  int info_log_length;
274  glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
275  if (info_log_length > 0)
276  {
277  vector<char> shader_error_message(info_log_length + 1);
278  glGetShaderInfoLog(shader_id, info_log_length, nullptr, &shader_error_message[0]);
279  stringstream error_stream;
280  error_stream << "Could not compile shader: " << (const char*)&shader_error_message[0];
281 
282  glDeleteShader(shader_id);
283  throw runtime_error(error_stream.str());
284  }
285  }
286  return shader_id;
287 }
288 
289 void mesh_filter::GLRenderer::readShaderCodeFromFile(const string& filename, string& shader) const
290 {
291  if (filename.empty())
292  shader = "";
293  else
294  {
295  string shader_code;
296  fstream shader_file(filename.c_str(), ios::in);
297  if (shader_file.is_open())
298  {
299  stringstream buffer;
300  buffer << shader_file.rdbuf();
301  shader = buffer.str();
302  }
303  else
304  {
305  stringstream error_stream;
306  error_stream << "Could not open shader code in file \"" << filename << "\"";
307  throw runtime_error(error_stream.str());
308  }
309  }
310 }
311 
312 GLuint mesh_filter::GLRenderer::loadShaders(const string& vertex_source, const string& fragment_source) const
313 {
314  if (vertex_source.empty() && fragment_source.empty())
315  return 0;
316 
317  GLuint program_id = glCreateProgram();
318  GLuint vertex_shader_id = 0;
319  GLuint fragment_shader_id = 0;
320 
321  if (!vertex_source.empty())
322  {
323  GLuint vertex_shader_id = createShader(GL_VERTEX_SHADER, vertex_source);
324  glAttachShader(program_id, vertex_shader_id);
325  }
326 
327  if (!fragment_source.empty())
328  {
329  GLuint fragment_shader_id = createShader(GL_FRAGMENT_SHADER, fragment_source);
330  glAttachShader(program_id, fragment_shader_id);
331  }
332 
333  glLinkProgram(program_id);
334 
335  // Check the program
336  GLint result = GL_FALSE;
337  GLint info_log_length;
338  glGetProgramiv(program_id, GL_LINK_STATUS, &result);
339  glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
340  if (info_log_length > 0)
341  {
342  vector<char> program_error_message(info_log_length + 1);
343  glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error_message[0]);
344  std::size_t l = strnlen(&program_error_message[0], program_error_message.size());
345  if (l > 0)
346  RCLCPP_ERROR(LOGGER, "%s\n", &program_error_message[0]);
347  }
348 
349  if (vertex_shader_id)
350  glDeleteShader(vertex_shader_id);
351 
352  if (fragment_shader_id)
353  glDeleteShader(fragment_shader_id);
354 
355  return program_id;
356 }
357 
358 map<std::thread::id, pair<unsigned, GLuint> > mesh_filter::GLRenderer::context_;
359 std::mutex mesh_filter::GLRenderer::context_lock_;
360 bool mesh_filter::GLRenderer::glutInitialized_ = false;
361 
362 namespace
363 {
364 void nullDisplayFunction()
365 {
366 }
367 } // namespace
368 
369 void mesh_filter::GLRenderer::createGLContext()
370 {
371  std::unique_lock<std::mutex> _(context_lock_);
372  if (!glutInitialized_)
373  {
374  char buffer[1];
375  char* args = buffer;
376  int n = 1;
377 
378  glutInit(&n, &args);
379  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
380  glutInitialized_ = true;
381  }
382 
383  // check if our thread is initialized
384  std::thread::id thread_id = std::this_thread::get_id();
385  map<std::thread::id, pair<unsigned, GLuint> >::iterator context_it = context_.find(thread_id);
386 
387  if (context_it == context_.end())
388  {
389  context_[thread_id] = std::pair<unsigned, GLuint>(1, 0);
390 
391  glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) + 30000, 0);
392  glutInitWindowSize(1, 1);
393  GLuint window_id = glutCreateWindow("mesh_filter");
394  glutDisplayFunc(nullDisplayFunction);
395 
396  GLenum err = glewInit();
397  if (GLEW_OK != err)
398  {
399  stringstream error_stream;
400  error_stream << "Unable to initialize GLEW: " << glewGetErrorString(err);
401 
402  throw(runtime_error(error_stream.str()));
403  }
404  glutIconifyWindow();
405  glutHideWindow();
406 
407  for (int i = 0; i < 10; ++i)
408  glutMainLoopEvent();
409 
410  context_[thread_id] = std::pair<unsigned, GLuint>(1, window_id);
411  }
412  else
413  ++(context_it->second.first);
414 }
415 
416 void mesh_filter::GLRenderer::deleteGLContext()
417 {
418  std::unique_lock<std::mutex> _(context_lock_);
419  std::thread::id thread_id = std::this_thread::get_id();
420  map<std::thread::id, pair<unsigned, GLuint> >::iterator context_it = context_.find(thread_id);
421  if (context_it == context_.end())
422  {
423  stringstream error_msg;
424  error_msg << "No OpenGL context exists for Thread " << thread_id;
425  throw runtime_error(error_msg.str());
426  }
427 
428  if (--(context_it->second.first) == 0)
429  {
430  glutDestroyWindow(context_it->second.second);
431  context_.erase(context_it);
432  }
433 }
434 
436 {
437  return rgb_id_;
438 }
439 
441 {
442  return depth_id_;
443 }
444 
446 {
447  return width_;
448 }
449 
451 {
452  return height_;
453 }
void getDepthBuffer(float *buffer) const
retrieves the depth buffer from OpenGL
void setBufferSize(unsigned width, unsigned height)
set the size of fram buffers
Definition: gl_renderer.cpp:84
void callList(GLuint list) const
executes a OpenGL list
GLuint getColorTexture() const
returns the handle of the color buffer as an OpenGL texture object
GLuint getDepthTexture() const
returns the handle of the depth buffer as an OpenGL texture object
unsigned getWidth() const
returns the width of the frame buffer objectsin pixels
void setCameraParameters(float fx, float fy, float cx, float cy)
set the camera parameters
GLRenderer(unsigned width, unsigned height, float near=0.1, float far=10.0)
constructs the frame buffer object in a new OpenGL context.
Definition: gl_renderer.cpp:58
void end() const
finalizes the frame buffers after rendering and/or manipulating
void begin() const
initializes the frame buffers for rendering and or manipulating
GLuint setShadersFromFile(const std::string &vertex_filename, const std::string &fragment_filename)
loads, compiles, links and adds GLSL shaders from files to the current OpenGL context.
void setClippingRange(float near, float far)
sets the near and far clipping plane distances in meters
Definition: gl_renderer.cpp:95
void getColorBuffer(unsigned char *buffer) const
retrieves the color buffer from OpenGL
unsigned getHeight() const
returns the height of the frame buffer objects in pixels
const float & getNearClippingDistance() const
returns the distance of the near clipping plane in meters
const float & getFarClippingDistance() const
returns the distance of the far clipping plane in meters
GLuint setShadersFromString(const std::string &vertex_shader, const std::string &fragment_shader)
loads, compiles, links and adds GLSL shaders from string to the current OpenGL context.
~GLRenderer()
destructor, destroys frame buffer objects and OpenGL context
Definition: gl_renderer.cpp:77
const GLuint & getProgramID() const
const rclcpp::Logger LOGGER
Definition: async_test.h:31