Commit e1f59e02 authored by Tim Übelhör's avatar Tim Übelhör

rewrite of the texture and framebuffer handling

parent ff49f339
project(scigl_render)
cmake_minimum_required(VERSION 2.8.3)
set (CMAKE_CXX_STANDARD 11)
# using conan to manage dependencies
if(CONAN_EXPORTED) # when packaging
......@@ -26,6 +27,7 @@ add_library(scigl_render
src/gl_context.cpp
src/buffer/frame_buffer.cpp
src/buffer/frame_buffer_reader.cpp
src/buffer/texture2d.cpp
src/render/depth_simulator.cpp
src/render/onscreen_render.cpp
src/render/rasterizer.cpp
......
#pragma once
#include <GL/gl3w.h>
#include <memory>
#include <scigl_render/buffer/texture2d.hpp>
namespace scigl_render
{
......@@ -15,11 +17,9 @@ public:
/*!
Creates the framebuffer with a rednerbuffer attachment to render to.
\throws a runtime_error on failure
\param width of the texture
\param height of the texture
\param internal_format color components & size of each
\param texture the texture to render to
*/
FrameBuffer(int width, int height, GLenum internal_format);
FrameBuffer(std::shared_ptr<Texture2D> texture);
FrameBuffer(const FrameBuffer &) = delete;
~FrameBuffer();
......@@ -41,19 +41,17 @@ public:
*/
void clear(float color = 0, float depth = 1, int stencil = 0) const;
/** returns the texture used for rendering */
GLuint get_texture() const;
/** returns the render target texture */
std::shared_ptr<Texture2D> get_texture() const;
/** gets the maximum rbo size */
static int get_max_size();
private:
// Parameterization
int width, height;
// framebuffer object to render the texture into
GLuint fbo;
// texture for renderng colors, can be sampled from
GLuint color_tex;
std::shared_ptr<Texture2D> color_tex;
// renderbuffer object for the depth testing, does not allow sampling
GLuint depth_stencil_rbo;
};
......
......@@ -18,20 +18,17 @@ class FramebufferReader
public:
/*!
Renders the scene off-screen and calculates the depth values.
\param width number of image columns
\param height number of image rows
\param buffer read from this framebuffer
\param pixel_size the size of each pixel: number_channels * sizeof(type)
*/
FramebufferReader(int width, int height, size_t pixel_size);
FramebufferReader(std::shared_ptr<FrameBuffer> buffer,
size_t pixel_size);
/*!
Starts reading from the FBO to the backbuffer PBO. This operation is
asynchronous.
\param format specifies the channels, for example GL_RGB
\param type primitive to store, for example GL_UNSIGNED_BYTE
\param buffer transfer data from this FBO to the PBO
*/
void start_read(GLenum format, GLenum type, const FrameBuffer& buffer) const;
void start_read() const;
/*!
Reads synchronously from the frontbuffer PBO. Operate on this data while
......@@ -49,8 +46,7 @@ public:
void swap_buffers();
private:
int width;
int height;
std::shared_ptr<FrameBuffer> framebuffer;
// Two pbos one to read to the other one to map form, alternating
std::array<GLuint, 2> pbos;
// transfer from fbo to pbo via glReadPixels
......
#pragma once
#include <GL/gl3w.h>
namespace scigl_render
{
/** RAII style creation of a 2D texture */
class Texture2D
{
public:
Texture2D(GLsizei width, GLsizei height,
GLenum format, GLenum internal_format, GLenum type);
Texture2D(const Texture2D &) = delete;
~Texture2D();
/** activates texture_n for use in shaders */
static void activate(GLenum texture_n);
/** binds this texture to GL_TEXTURE_2D */
void bind() const;
/** unbinds this texture */
void unbind() const;
/** upload an image to the texture. */
void store_image(const GLvoid *image) const;
GLuint get_raw() const;
GLsizei get_width() const;
GLsizei get_height() const;
GLenum get_format() const;
GLenum get_internal_format() const;
GLenum get_type() const;
private:
const GLsizei width, height;
const GLenum format, internal_format, type;
GLuint texture;
};
} // namespace scigl_render
\ No newline at end of file
......@@ -22,17 +22,14 @@ class DepthOffscreenRender
public:
/*!
Configures the rendering environment and loads the models.
\param context the environment to configure
\param shader how to render the scene
\param tex_format format parameter of glTexImage2D
\param tex_type type parameter of glTexImage2D
\param tex_internal_format internal_format parameter of glTexImage2D
\param context the environment to render to (swap Buffers)
\param texture parametrized for offscreen rendering
\param pixel_size the size of one pixel. Must match the internal format:
number_of_channels * sizeof(type)
*/
DepthOffscreenRender(
std::shared_ptr<GLContext> context, GLenum tex_format, GLenum tex_type,
GLint tex_internal_format, size_t pixel_size);
DepthOffscreenRender(std::shared_ptr<GLContext> context,
std::shared_ptr<Texture2D>,
size_t pixel_size);
/*!
Continues to render the next frame.
......@@ -41,26 +38,20 @@ public:
const CartesianPose &model_pose,
const CartesianPose &camera_pose);
/*!
Resizes the buffers to the screen size of the GLContext.
*/
void resize_buffers();
private:
// parameters for rendering
GLenum texture_format;
GLenum texture_type;
GLenum texture_internal_format;
size_t pixel_size;
std::shared_ptr<GLContext> gl_context;
// Render targets
FrameBuffer framebuffer;
FramebufferReader fbo_reader;
// render to fbo
std::shared_ptr<Texture2D> fbo_texture;
std::shared_ptr<FrameBuffer> framebuffer;
std::unique_ptr<FramebufferReader> fbo_reader;
// display fullscreen quad from other texture (to showcase the mapping)
TextureFullscreenRender texture_render;
// buffer for reading from the offscreen render
std::vector<unsigned char> image_buffer;
std::shared_ptr<Texture2D> quad_texture;
// display different views
Rasterizer rasterizer;
// CPU memory buffer for reading from the offscreen render
std::vector<uint8_t> image_buffer;
/*!
Display the data from the framebuffer
......
#pragma once
#include <memory>
#include <scigl_render/buffer/texture2d.hpp>
#include <scigl_render/shader/shader.hpp>
namespace scigl_render
......@@ -14,24 +16,15 @@ public:
Create the renderer with a texture storage with the given format.
\param internal_format the internal format used in glTexStorage2D
*/
TextureFullscreenRender(int width, int height,
GLint internal_format = GL_RGB8);
TextureFullscreenRender();
/*!
Draws the pixels into the currently selected framebuffer. This function
changes glDepthFunc(GL_LEQUAL) so the quad can be seen (z = 1.0).
\param pixels the pointer to the lower left pixel of the image
\param format format of a pixel for example GL_RGB
\param type the type of the storage for example GL_UNSIGNED_BYTE
/**
* Draws the contents of the texture to a fullscreen quad.
* Changes glDepthFunc(GL_LEQUAL) so the quad can be seen (z = 1.0).
*/
void draw(const GLvoid *pixels, GLenum format, GLenum type);
void draw(std::shared_ptr<Texture2D> texture) const;
private:
// store the texture here for rendering
GLuint texture;
// properties of the image
GLsizei width;
GLsizei height;
// Dummy VAO since the geometry shader creates the vertices
GLuint vao;
Shader shader;
......
......@@ -3,21 +3,21 @@
namespace scigl_render
{
FrameBuffer::FrameBuffer(int width, int height, GLenum internal_format)
FrameBuffer::FrameBuffer(std::shared_ptr<Texture2D> texture)
: color_tex(texture)
{
this->width = width;
this->height = height;
// Create framebuffer with renderbuffer attachements
glGenFramebuffers(1, &fbo);
activate();
glGenTextures(1, &color_tex);
glBindTexture(GL_TEXTURE_2D, color_tex);
glTexStorage2D(GL_TEXTURE_2D, 1, internal_format, width, height);
color_tex->bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, color_tex, 0);
GL_TEXTURE_2D, color_tex->get_raw(), 0);
color_tex->unbind();
glGenRenderbuffers(1, &depth_stencil_rbo);
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glRenderbufferStorage(
GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
color_tex->get_width(), color_tex->get_height());
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_rbo);
......@@ -33,7 +33,6 @@ FrameBuffer::~FrameBuffer()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteRenderbuffers(1, &depth_stencil_rbo);
glDeleteTextures(1, &color_tex);
}
void FrameBuffer::activate() const
......@@ -56,7 +55,7 @@ void FrameBuffer::clear(float color, float depth, int stencil) const
deactivate();
}
GLuint FrameBuffer::get_texture() const
std::shared_ptr<Texture2D> FrameBuffer::get_texture() const
{
return color_tex;
}
......
......@@ -5,30 +5,38 @@
namespace scigl_render
{
FramebufferReader::FramebufferReader(int width, int height, size_t pixel_size)
: width(width), height(height)
FramebufferReader::FramebufferReader(std::shared_ptr<FrameBuffer> buffer,
size_t pixel_size)
: framebuffer(buffer)
{
glGenBuffers(pbos.size(), pbos.data());
size_t buffer_size = framebuffer->get_texture()->get_width() *
framebuffer->get_texture()->get_height() *
pixel_size;
for (size_t i = 0; i < pbos.size(); i++)
{
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbos[i]);
// constantly reading new contents
glBufferData(GL_PIXEL_PACK_BUFFER, width * height * pixel_size, 0,
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, 0,
GL_DYNAMIC_READ);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
check_gl_error("framebuffer-reader created pbos");
}
void FramebufferReader::start_read(GLenum format, GLenum type,
const FrameBuffer &buffer) const
void FramebufferReader::start_read() const
{
buffer.activate();
framebuffer->activate();
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbos[backbuffer_index]);
glReadPixels(0, 0, width, height, format, type, nullptr);
glReadPixels(0, 0,
framebuffer->get_texture()->get_width(),
framebuffer->get_texture()->get_height(),
framebuffer->get_texture()->get_format(),
framebuffer->get_texture()->get_type(),
nullptr);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
buffer.deactivate();
framebuffer->deactivate();
}
void *FramebufferReader::do_read() const
......
#include <scigl_render/buffer/texture2d.hpp>
namespace scigl_render
{
Texture2D::Texture2D(GLsizei width, GLsizei height,
GLenum format, GLenum internal_format, GLenum type)
: width(width), height(height),
format(format), internal_format(internal_format),
type(type)
{
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, internal_format, width, height);
glBindTexture(GL_TEXTURE_2D, 0);
}
Texture2D::~Texture2D()
{
glDeleteTextures(1, &texture);
}
GLuint Texture2D::get_raw() const
{
return texture;
}
GLsizei Texture2D::get_width() const
{
return width;
}
GLsizei Texture2D::get_height() const
{
return height;
}
GLenum Texture2D::get_format() const
{
return format;
}
GLenum Texture2D::get_internal_format() const
{
return internal_format;
}
GLenum Texture2D::get_type() const
{
return type;
}
void Texture2D::activate(GLenum texture_n)
{
glActiveTexture(texture_n);
}
void Texture2D::bind() const
{
glBindTexture(GL_TEXTURE_2D, texture);
}
void Texture2D::unbind() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture2D::store_image(const GLvoid *image) const
{
bind();
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, image);
unbind();
}
} // namespace scigl_render
......@@ -4,31 +4,24 @@
namespace scigl_render
{
// I know there is a lot of configuration but it is intendet to be flexible
DepthOffscreenRender::DepthOffscreenRender(
std::shared_ptr<GLContext> context,
GLenum tex_format, GLenum tex_type, GLint tex_internal_format,
size_t pixel_size)
: texture_format(tex_format),
texture_type(tex_type),
texture_internal_format(tex_internal_format),
pixel_size(pixel_size),
gl_context(context),
framebuffer(gl_context->get_width(),
gl_context->get_height(),
tex_internal_format),
fbo_reader(gl_context->get_width(),
gl_context->get_height(),
pixel_size),
texture_render(gl_context->get_width(),
gl_context->get_height(),
tex_internal_format),
image_buffer(gl_context->get_width() * gl_context->get_height() *
DepthOffscreenRender::DepthOffscreenRender(std::shared_ptr<GLContext> context,
std::shared_ptr<Texture2D> texture,
size_t pixel_size)
: rasterizer(context->get_width() / 2, context->get_height() / 2,
2, 2),
image_buffer(context->get_width() * context->get_height() *
pixel_size),
rasterizer(gl_context->get_width() / 2,
gl_context->get_height() / 2,
2, 2)
gl_context(context),
fbo_texture(texture)
{
check_gl_error("example render created");
framebuffer = std::make_shared<FrameBuffer>(fbo_texture);
fbo_reader = std::unique_ptr<FramebufferReader>(
new FramebufferReader(framebuffer, pixel_size));
// create second texture to copy the data to
quad_texture = std::make_shared<Texture2D>(
fbo_texture->get_width(), fbo_texture->get_height(),
fbo_texture->get_format(), fbo_texture->get_internal_format(),
fbo_texture->get_type());
}
void DepthOffscreenRender::next_frame(
......@@ -39,10 +32,9 @@ void DepthOffscreenRender::next_frame(
using namespace std::placeholders;
check_gl_error("next frame begin");
// render to cleared fbo
framebuffer.clear();
framebuffer.activate();
framebuffer->clear();
framebuffer->activate();
check_gl_error("activated fbo");
// render 4 poses via rasterization
for (int i = 0; i < 4; i++)
{
......@@ -54,16 +46,18 @@ void DepthOffscreenRender::next_frame(
}
// back to default
rasterizer.activate_all();
framebuffer.deactivate();
framebuffer->deactivate();
// read data from fbo
fbo_reader.start_read(texture_format, texture_type, framebuffer);
fbo_reader->start_read();
check_gl_error("asynchronous reading to pbo");
auto data = fbo_reader.do_read();
auto data = fbo_reader->do_read();
check_gl_error("synchronous reading from pbo");
// display the data on screen
display_data(data);
fbo_reader.end_read();
fbo_reader.swap_buffers();
fbo_reader->end_read();
fbo_reader->swap_buffers();
check_gl_error("end synchronous reading");
}
......@@ -71,30 +65,13 @@ void DepthOffscreenRender::display_data(const void *data)
{
// Test copying the data, buffer_size is in bytes
memcpy(image_buffer.data(), data, image_buffer.size());
quad_texture->store_image(data);
// draw the copy
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
texture_render.draw(image_buffer.data(), texture_format, texture_type);
texture_render.draw(quad_texture);
check_gl_error("drawing fullscreen quad");
// update
glfwSwapBuffers(gl_context->get_window());
}
void DepthOffscreenRender::resize_buffers()
{
framebuffer = FrameBuffer(
gl_context->get_width(),
gl_context->get_height(),
texture_internal_format);
fbo_reader = FramebufferReader(
gl_context->get_width(),
gl_context->get_height(),
pixel_size);
texture_render = TextureFullscreenRender(
gl_context->get_width(),
gl_context->get_height(),
texture_internal_format),
image_buffer = std::vector<unsigned char>(
gl_context->get_width() * gl_context->get_height() * pixel_size);
}
} // namespace scigl_render
\ No newline at end of file
......@@ -39,11 +39,12 @@ int main(int argc, char *argv[])
"No model file provided. Run as */scigl_viwer <model_filename>!");
}
// Setup renderer creates context
std::shared_ptr<GLContext> context =
std::make_shared<GLContext>(true, false, WIDTH, HEIGHT);
auto context = std::make_shared<GLContext>(true, false, WIDTH, HEIGHT);
check_gl_error("Context created");
DepthOffscreenRender render(context, GL_RED, GL_FLOAT, GL_R32F,
sizeof(float));
auto texture = std::make_shared<Texture2D>(
WIDTH, HEIGHT, GL_RED, GL_R32F, GL_FLOAT);
check_gl_error("texture created");
DepthOffscreenRender render(context, texture, sizeof(float));
// Intrinsics of my shitty webcam
CameraIntrinsics camera_intrinsics;
camera_intrinsics.width = 640;
......
......@@ -24,20 +24,13 @@ void main()
color = texture(texture0, texture_coordinate);
})";
TextureFullscreenRender::TextureFullscreenRender(
int width, int height, GLint internal_format)
: width(width), height(height)
TextureFullscreenRender::TextureFullscreenRender()
{
ShaderBuilder shader_builder;
shader_builder.attach_vertex_shader(vertex_source);
shader_builder.attach_geometry_shader(geometry_source);
shader_builder.attach_fragment_shader(fragment_source);
shader = shader_builder.build();
// create the texture buffer
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, internal_format, width, height);
glBindTexture(GL_TEXTURE_2D, 0);
// create dummy VAO
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
......@@ -45,23 +38,20 @@ TextureFullscreenRender::TextureFullscreenRender(
check_gl_error("TextureFullscreenRender created");
}
void TextureFullscreenRender::draw(
const GLvoid *pixels, GLenum format, GLenum type)
void TextureFullscreenRender::draw(std::shared_ptr<Texture2D> texture) const
{
// With GL_LESS the cleared buffer (z = 1.0) would always win
glDepthFunc(GL_LEQUAL);
// activate the shader and texure
shader.activate();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// copy data to OpenGL
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, pixels);
// draw the image
texture->bind();
Texture2D::activate(GL_TEXTURE0);
shader.setInt("texture0", 0);
glBindVertexArray(vao);
glDrawArrays(GL_POINTS, 0, 1);
// unbind the resources
glBindTexture(GL_TEXTURE_2D, 0);
shader.deactivate();
texture->unbind();
glBindVertexArray(0);
}
} // namespace scigl_render
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment