Antialiasing with post processing ( view port filter )
Antialiasing (AA) is old topic for computer graphic since the structure of PC screen is measure by pixel and there is no way to create a unit samller than that, we have no choice but using a way named antialiasing to avoid the jaggy on the edge of the objects. Complicated as it seems to be, the real instinct behide antialiasing is simple --- enlarge( maybe called stretch) the original image and shrink it using a fliter, e.g. Nearest neighbor, Linear, etc. At the very beginning the solution is calculated with CPU and a new way to manange is introduced by graphic card vendor, which takes advantage of the GPU, called Full Screen Antialiasing (FSAA). As you may imagine, different vendors have their own way to handle things. Nvidia raises his idea by applied the AA effect on the entire screen named Super Sampling Antialiasing (SSAA). At the other side, ATI uses a another approach called Multisampling Antialiasing (MSAA), which calculate the edge of the polygons only. Apperently, the approach that ATI employed is much faster due to the area of calculation is a lot smaller than what NVidia need to take care of. However, winner of the quality result is Nvidia. As time passes, the mipmapping and anistropic filter appear, which make it very unneccessay for applying aa effect inside the polygon because there will be textured.Also, the FSAA supported by hardware is not effectable when we are using render target (RT) in DirectX or Frame Buffer object (FBO) in opengl. Now, the way of applying the aa effect as the post processing to RT and FBO is described here.
OpenGL:
1, Create a normal FBO attached with textures like color buffers, depth and stencil buffer.
2, Create another FBO attached with multisample render buffers which need to be EXACTLY corresponding with the first one. e.g. If you need to have 2 color bufer and 1 depth buffer, you need to create 2 multisample colors buffer to have MSAA effect and one multisample depth render buffer because a FBO can not mixed single sample and multisample render buffer.This resolution mismatch between the real back buffer size and the application’s view of it is the reason why you can’t attach a multisampled z buffer to a non-multisampled render target.
3, Bind the multisample FBO before rendering to FBO.
4, After the redering, read from the multisample FBO and write to the normal FBO, then "Blit" the two FBOs.
Take a example of create a multisample on a FBO with one color buffer and depth buffer,
Init Normal FBO:
Init Multisample FBO:
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorRenderbufferName);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, 4, GL_RGBA, m_iWidth, m_iHeight);
![]()
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferRenderName);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, colorRenderbufferName);
![]()
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRenderBufferName);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, 4, GL_DEPTH_COMPONENT, m_iWidth, m_iHeight);
![]()
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferRenderName);
![]()
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthRenderBufferName);
Before rendering:
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferRenderName);
After rendering:
DriectX:
The idea is similar and the key function is stretchRect which will resize the source buffer to the destination buffer with a filter. Then render the back buffer form one RT to another until the tail of the RT list. If u feel interesting on how to implement this in DirectX , you can download the sample form NVidia Developer SDK.
Conclusion:
I didnt update my blog for a long time, but I will continue my development research in the future because my new company provide me a very positive enviornment to be a good enginner and a good reseacher.
OpenGL:
1, Create a normal FBO attached with textures like color buffers, depth and stencil buffer.
2, Create another FBO attached with multisample render buffers which need to be EXACTLY corresponding with the first one. e.g. If you need to have 2 color bufer and 1 depth buffer, you need to create 2 multisample colors buffer to have MSAA effect and one multisample depth render buffer because a FBO can not mixed single sample and multisample render buffer.This resolution mismatch between the real back buffer size and the application’s view of it is the reason why you can’t attach a multisampled z buffer to a non-multisampled render target.
3, Bind the multisample FBO before rendering to FBO.
4, After the redering, read from the multisample FBO and write to the normal FBO, then "Blit" the two FBOs.
Take a example of create a multisample on a FBO with one color buffer and depth buffer,
Init Normal FBO:
1
glGenTextures(1, &colorTextureName);
2
glBindTexture(GL_TEXTURE_2D, colorTextureName);
3
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
4
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
6
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
7
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
8![]()
9
glGenFramebuffersEXT(1, &framebufferResolvedName);
10
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferResolvedName);
11
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colorTextureName, 0);
12![]()
13
glGenTextures(1, &depthTextureName);
14
glBindTexture(GL_TEXTURE_2D, colorTextureName);
15![]()
16
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, iWidth, iHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0 );
17![]()
18
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
19
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
20![]()
21
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
22
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
23![]()
24
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colorTextureName, 0);
25
if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
26
return false;
27
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
28![]()
glGenTextures(1, &colorTextureName);2
glBindTexture(GL_TEXTURE_2D, colorTextureName);3
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);4
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);5
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);6
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);7
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);8

9
glGenFramebuffersEXT(1, &framebufferResolvedName);10
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferResolvedName);11
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colorTextureName, 0);12

13
glGenTextures(1, &depthTextureName);14
glBindTexture(GL_TEXTURE_2D, colorTextureName);15

16
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, iWidth, iHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0 );17

18
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);19
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);20

21
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);22
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);23

24
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colorTextureName, 0);25
if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)26
return false;27
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);28

Init Multisample FBO:
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorRenderbufferName);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, 4, GL_RGBA, m_iWidth, m_iHeight);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferRenderName);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, colorRenderbufferName);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRenderBufferName);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, 4, GL_DEPTH_COMPONENT, m_iWidth, m_iHeight);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferRenderName);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthRenderBufferName);Before rendering:
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferRenderName);After rendering:
1
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, framebufferRenderName);
2
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_iFramebufferHandle);
3
glBlitFramebufferEXT(0, 0, m_iWidth, m_iHeight, 0, 0, m_iWidth, m_iHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
4![]()
5
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, framebufferRenderName);2
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_iFramebufferHandle);3
glBlitFramebufferEXT(0, 0, m_iWidth, m_iHeight, 0, 0, m_iWidth, m_iHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);4

5
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);DriectX:
The idea is similar and the key function is stretchRect which will resize the source buffer to the destination buffer with a filter. Then render the back buffer form one RT to another until the tail of the RT list. If u feel interesting on how to implement this in DirectX , you can download the sample form NVidia Developer SDK.
Conclusion:
I didnt update my blog for a long time, but I will continue my development research in the future because my new company provide me a very positive enviornment to be a good enginner and a good reseacher.
浙公网安备 33010602011771号