Offscreen Rendering and Multisampling With OpenGL

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int fbo, colorBuffer, depthBuffer;

// Create and bind the FBO
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);

// Create color render buffer
glGenRenderbuffers(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 texture
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, aTexture, 0);

// Draw something
drawGraphic();

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Create multisample texture
glBindTexture(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 FBO
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);

// Create color render buffer
glGenRenderbuffers(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 texture
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, aTexture, 0);

// Enable multisampling
glEanble(GL_MULTISAMPLE);

// Draw something
drawGraphic();

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
1
2
3
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/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值