39 #include <OpenGL/glu.h> 
   44 #include <GL/freeglut.h> 
   51 #include <rclcpp/logger.hpp> 
   52 #include <rclcpp/logging.hpp> 
   56 static const rclcpp::Logger 
LOGGER = rclcpp::get_logger(
"moveit.ros.perception.gl_renderer");
 
   79   glDeleteProgram(program_);
 
   86   if (width_ != width || height_ != height)
 
   98     throw runtime_error(
"near clipping plane distance needs to be larger than 0");
 
  100     throw runtime_error(
"far clipping plane needs to be larger than near clipping plane distance");
 
  113 void mesh_filter::GLRenderer::setCameraParameters()
 const 
  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_;
 
  120   glMatrixMode(GL_PROJECTION);
 
  122   glFrustum(left, right, bottom, top, near_, far_);
 
  124   glMatrixMode(GL_MODELVIEW);
 
  126   gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0);
 
  129 void mesh_filter::GLRenderer::initFrameBuffers()
 
  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);
 
  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);
 
  149   glGenFramebuffers(1, &fbo_id_);
 
  150   glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
 
  151   glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgb_id_, 0);
 
  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);
 
  160   GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
 
  161   glDrawBuffers(2, draw_buffers);
 
  163   GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
  165   if (status != GL_FRAMEBUFFER_COMPLETE)  
 
  166     throw runtime_error(
"Couldn't create frame buffer");
 
  168   glBindFramebuffer(GL_FRAMEBUFFER, 0);  
 
  171 void mesh_filter::GLRenderer::deleteFrameBuffers()
 
  174     glDeleteRenderbuffers(1, &rbo_id_);
 
  176     glDeleteFramebuffers(1, &fbo_id_);
 
  178     glDeleteTextures(1, &depth_id_);
 
  180     glDeleteTextures(1, &rgb_id_);
 
  182   rbo_id_ = fbo_id_ = depth_id_ = rgb_id_ = 0;
 
  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();
 
  206   glBindFramebuffer(GL_FRAMEBUFFER, 0);
 
  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);
 
  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);
 
  228     glDeleteProgram(program_);
 
  230   string vertex_source, fragment_source;
 
  231   readShaderCodeFromFile(vertex_filename, vertex_source);
 
  232   readShaderCodeFromFile(fragment_filename, fragment_source);
 
  234   program_ = loadShaders(vertex_source, fragment_source);
 
  240   program_ = loadShaders(vertex_source, fragment_source);
 
  259 GLuint mesh_filter::GLRenderer::createShader(GLuint shaderType, 
const string& ShaderCode)
 const 
  261   GLuint shader_id = glCreateShader(shaderType);
 
  264   char const* source_pointer = ShaderCode.c_str();
 
  265   glShaderSource(shader_id, 1, &source_pointer, 
nullptr);
 
  266   glCompileShader(shader_id);
 
  269   GLint result = GL_FALSE;
 
  270   glGetShaderiv(shader_id, GL_COMPILE_STATUS, &result);
 
  271   if (result != GL_TRUE)
 
  274     glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
 
  275     if (info_log_length > 0)
 
  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];
 
  282       glDeleteShader(shader_id);
 
  283       throw runtime_error(error_stream.str());
 
  289 void mesh_filter::GLRenderer::readShaderCodeFromFile(
const string& filename, 
string& shader)
 const 
  291   if (filename.empty())
 
  296     fstream shader_file(filename.c_str(), ios::in);
 
  297     if (shader_file.is_open())
 
  300       buffer << shader_file.rdbuf();
 
  301       shader = buffer.str();
 
  305       stringstream error_stream;
 
  306       error_stream << 
"Could not open shader code in file \"" << filename << 
"\"";
 
  307       throw runtime_error(error_stream.str());
 
  312 GLuint mesh_filter::GLRenderer::loadShaders(
const string& vertex_source, 
const string& fragment_source)
 const 
  314   if (vertex_source.empty() && fragment_source.empty())
 
  317   GLuint program_id = glCreateProgram();
 
  318   GLuint vertex_shader_id = 0;
 
  319   GLuint fragment_shader_id = 0;
 
  321   if (!vertex_source.empty())
 
  323     GLuint vertex_shader_id = createShader(GL_VERTEX_SHADER, vertex_source);
 
  324     glAttachShader(program_id, vertex_shader_id);
 
  327   if (!fragment_source.empty())
 
  329     GLuint fragment_shader_id = createShader(GL_FRAGMENT_SHADER, fragment_source);
 
  330     glAttachShader(program_id, fragment_shader_id);
 
  333   glLinkProgram(program_id);
 
  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)
 
  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());
 
  346       RCLCPP_ERROR(LOGGER, 
"%s\n", &program_error_message[0]);
 
  349   if (vertex_shader_id)
 
  350     glDeleteShader(vertex_shader_id);
 
  352   if (fragment_shader_id)
 
  353     glDeleteShader(fragment_shader_id);
 
  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;
 
  364 void nullDisplayFunction()
 
  369 void mesh_filter::GLRenderer::createGLContext()
 
  371   std::unique_lock<std::mutex> _(context_lock_);
 
  372   if (!glutInitialized_)
 
  379     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
 
  380     glutInitialized_ = 
true;
 
  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);
 
  387   if (context_it == context_.end())
 
  389     context_[thread_id] = std::pair<unsigned, GLuint>(1, 0);
 
  391     glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) + 30000, 0);
 
  392     glutInitWindowSize(1, 1);
 
  393     GLuint window_id = glutCreateWindow(
"mesh_filter");
 
  394     glutDisplayFunc(nullDisplayFunction);
 
  396     GLenum err = glewInit();
 
  399       stringstream error_stream;
 
  400       error_stream << 
"Unable to initialize GLEW: " << glewGetErrorString(err);
 
  402       throw(runtime_error(error_stream.str()));
 
  407     for (
int i = 0; i < 10; ++i)
 
  410     context_[thread_id] = std::pair<unsigned, GLuint>(1, window_id);
 
  413     ++(context_it->second.first);
 
  416 void mesh_filter::GLRenderer::deleteGLContext()
 
  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())
 
  423     stringstream error_msg;
 
  424     error_msg << 
"No OpenGL context exists for Thread " << thread_id;
 
  425     throw runtime_error(error_msg.str());
 
  428   if (--(context_it->second.first) == 0)
 
  430     glutDestroyWindow(context_it->second.second);
 
  431     context_.erase(context_it);
 
void getDepthBuffer(float *buffer) const
retrieves the depth buffer from OpenGL
 
void setBufferSize(unsigned width, unsigned height)
set the size of fram buffers
 
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.
 
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
 
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
 
const GLuint & getProgramID() const
 
const rclcpp::Logger LOGGER