Offscreen Rendering and Multisampling With OpenGL

来源:互联网 发布:c语言else语句格式 编辑:程序博客网 时间:2024/04/29 01:54

It has been for a while since my last post. I was enjoying with my senior project, “Accelerating Map Rendering with GPU”. In this project, my friend and I modified Mapnik, an opensource map rendering, to utilize Nvidia’s Path Rendering. Path Rendering is an OpenGL extension provided by Nvidia for vector graphic rendering. Nvidia claims that its extensions aims to reduce overhead from traditional APIs when using them to draw vector graphics. In the end, we are able to make the map production 30-60% faster. Our implementation can be found on https://github.com/ake-koomsin/mapnik_nvpr

There are two important things that we had to achieve in order to use Path Rendering extension for map rendering, offscreen rendering and multisampling. Offscreen rendering is important because we don’t want the renderer to show the intermediate result. Multisampling is for producing a quality map.

I think offscreen rendering combining with multisampling is an important piece of knowledge. It is also hard to find a complete refernce about these two. Therefore, I think it is worth writing about it.

Offscreen Rendering

Offscreen rendering is a technique that are commonly found in game development. Sometimes, there are situations that you want to generate a texture at runtime.

To set up offscreen rendering, you have to create your own “Framebuffer Object (FBO)”. Actually, OpenGL has its own default FBO. A result stored in the default FBO will be shown onto the screen while the result stored in our own FBO will be not. The code below demonstrates how to set up our own FBO.

Setting our own FBO for offscreen rendering
123456789101112131415161718192021222324
int fbo, colorBuffer, depthBuffer;// Create and bind the FBOglGenFramebuffers(1, &fbo);glBindFramebuffer(GL_FRAMEBUFFER, fbo);// Create color render bufferglGenRenderbuffers(1, &colorBuffer);glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);// Create depth render buffer (This is optional)glGenRenderbuffers(1, &depthBuffer);glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);// Bind Texture assuming we have created a textureglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, aTexture, 0);// Draw somethingdrawGraphic();

It is straightforward. First, we create a FBO. After that, we create render buffers and textures and attach them to our FBO.

Multisampling

By default, OpenGL does not care about antialiasing. As a result, the output contains stair-like artifacts which degrade visual quality. We have to enable multisampling by the code below.

Enabling multisampling
1
glEanble(GL_MULTISAMPLE);

Combining Offscreen Rendering and Multisampling Together

It turns out that to combine them together, we need additional set up which are multisample framebuffer storage and multisample texture. The code below demonstrates how to do.

Setting up FBO with Multisampling
12345678910111213141516171819202122232425262728293031
// Create multisample textureglBindTexture(GL_TEXTURE_2D_MULTISAMPLE, aMultisampleTexture);glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 16, GL_RGBA, width, height, GL_TRUE);int fbo, colorBuffer, depthBuffer;// Create and bind the FBOglGenFramebuffers(1, &fbo);glBindFramebuffer(GL_FRAMEBUFFER, fbo);// Create color render bufferglGenRenderbuffers(1, &colorBuffer);glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);glRenderbufferStorageMultisample(GL_RENDERBUFFER, 16, GL_RGBA8, width, height);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);// Create depth render buffer (This is optional)glGenRenderbuffers(1, &depthBuffer);glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);glRenderbufferStorageMultisample(GL_RENDERBUFFER, 16, GL_DEPTH24_STENCIL8, width, height);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);// Bind Texture assuming we have created a textureglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, aTexture, 0);// Enable multisamplingglEanble(GL_MULTISAMPLE);// Draw somethingdrawGraphic();

Retrieving the result

After offscreen rendering, you may want to display the result onto the screen. When you are using multisampling FBO, you are not able to use the result stored in the texture directly. You have to do “Blitting” which transfer the result from one FBO to another. The code below shows how to do.

Blitting
123
glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO);glBindFramebuffer(GL_DRAW_FRAMEBUFFER, normalFBO); // Normal FBO can be the default FBO too.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);

I hope these snippets are a useful reference.


http://ake.in.th/2013/04/02/offscreening-and-multisampling-with-opengl/

0 0