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