关于支持多重采样的FBO和Texture

闲话不唠,简单粗暴版。

  简单提一句MSAA(Multisample Anti Aliasing),依本人愚见,MSAA就是光栅化阶段对一个像素内部进行多次采样(采4次就是4X,采8次就是8X多重采样),然后根据按照一定规则(默认是取平均值)将同一个像素内的多个采样点融合成一个的过程(resolve 过程)。

  先讲简单的版本,从OpenGL的使用角度上讲,多重采样可以分为两种,context-based 和 Fbo-based。

  Context-based Multisample需要显式(明确地,explicitly)创建一个支持多重采样的上下文(OpenGL Render Context)。使用时只需要调用glEnable(GL_MULTISAMPLE),那么接下来要渲染的物体都会进行多重采样。轻松加愉快! 前提是你使用GLUT、GLFW等库,可以很简单地通过调用一个函数来创建支持多重采样渲染环境的窗口。但是!当你像我一样,要基于win32 或者 mfc构建OpenGL 应用程序时,这个过程就相对复杂一点。此过程在之前的随笔中有讲到,要先创建窗口、建立临时context、初始化glew库,获得相关函数指针、销毁原窗口,创建新context等等操作,在此按下不表。

  Fbo-based Multisample不需要显式地去创建一个支持多重采样的上下文。采用这种方法给了我们更多的灵活性。Fbo-based Multisample也可以分为小两种。第一种,渲染到RenderBuffer,然后调用glBlitFramebuffer到default framebuffer。采用第一种方法,多重采样的resolve过程由glBlitFramebuffer完成了,所以我们不用担心这个环节。第二种:渲染到Texture,然后在fragment shader中手动地对 sample 进行 resolve 操作。默认的resolve是取平均值的,现在我们可以在fragment shader中获取各个sample的值,要怎么resolve,决定权在你,这就是所谓的灵活性。



萝莉啰嗦,全程代码版

  第一种!基于OpenGL Context的多重渲染。实在没啥好讲的。重点完全在于如何建立支持多重渲染的Context。好麻烦的,但是我在之前的随笔中有讲到,以Nehe的代码为例(我还是把Nehe的原版代码也贴上吧,免得以后找不着)。注意,在创建支持多重采样的渲染环境时,有一段代码是OpenGL环境设置的,如下:

 1 int iAttributes[] =
 2     {
 3         WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
 4         WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
 5         WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
 6             WGL_COLOR_BITS_ARB,24,
 7             WGL_ALPHA_BITS_ARB,8,
 8             WGL_DEPTH_BITS_ARB,24,
 9             WGL_STENCIL_BITS_ARB,0,
10             WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
11             WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,  //!要将多重采样使用的buffers设置为真。
12             WGL_SAMPLES_ARB,4,          //!在此设置采样点的数量。
13             0,0
14     };
15
16     //First We Check To See If we can get a pixel format for 4 Samples
17     valid = wglChoosePixelFormatARB(hDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);

  注意设置采样缓冲区为真,设置采样点数量就ok了,别的没啥好说的。渲染的时候调用glEnable(GL_MULTISAMPLE)就好了。



  第二种!这个值得说道下!

  先说下FBO渲染到RenderBuffer的多重采样方式吧。 Talk is chear, show me the code!

  

 1    glGenRenderbuffers(1,&m_multiSampleColor);
 2     glBindRenderbuffer(GL_RENDERBUFFER,m_multiSampleColor);
 3     glRenderbufferStorageMultisample(GL_RENDERBUFFER,4,GL_RGBA8,m_width,m_height);  //与普通Renderbuffer不同的是,在分配空间时,我们调用glRenderBufferStorageMultisample(),第二个参数是采样数。
 4
 5     glGenFramebuffers(1,&m_multiSampleFBO);
 6     glBindFramebuffer(GL_FRAMEBUFFER,m_multiSampleFBO);
 7
 8     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,m_multiSampleColor);
 9
10
11     //glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D_MULTISAMPLE,m_texID,0);
12
13     glGenRenderbuffers(1,&m_multiSampleDepth);
14     glBindRenderbuffer(GL_RENDERBUFFER,m_multiSampleDepth);
15     glRenderbufferStorageMultisample(GL_RENDERBUFFER,4,GL_DEPTH_COMPONENT,m_width,m_height);  //用作Depth Test的RenderBuffer也一样,要调用glRenderBufferStorageMultisample()
16
17
18     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,m_multiSampleDepth);
19
20     GLenum drawBufs[] = {GL_COLOR_ATTACHMENT0};
21     glDrawBuffers(1, drawBufs);
22
23     GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
24     if( result == GL_FRAMEBUFFER_COMPLETE) {
25         printf("Framebuffer complete!\n");
26     } else {
27         printf("Framebuffer incomplete!\n");
28     }

  注意上面的代码红色标注的部分,与普通Renderbuffer不同的是,用于多重采样渲染的Renderbuffer需要调用glRenderbufferStorageMultisample来为Renderbuffer分配空间,第二个参数为采样点个数。

  以上是Framebuffer的初始化部分。以下是渲染的部分:

 1     glBindFramebuffer(GL_FRAMEBUFFER,m_multiSampleFBO);  //绑定你之前申请的FBO
 2
 3     // Shader Programs,Setup Matrices, Light, Materials,  And Render Whatever You Want To Render Here!       //放开了画吧,骚年!
 4
 5     glBindFramebuffer(GL_READ_FRAMEBUFFER,m_multiSampleFBO);  //设定之前的FBO为将要读取的Framebuffer
 6     glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0);           //设定屏幕(default framebuffer)为将要写入的Framebuffer
 7     glBlitFramebuffer(0,0,m_width,m_height,0,0,m_width,m_height,GL_COLOR_BUFFER_BIT,GL_NEAREST);  //传送FBO的ColorBuffer到default framebuffer的ColorBuffer去,期间进行了Multisample的Resolve操作。
 8     glBlitFramebuffer(0,0,m_width,m_height,0,0,m_width,m_height,GL_DEPTH_BUFFER_BIT,GL_NEAREST);  //传送FBO的DepthBuffer到default framebuffer的DepthBuffer去,期间进行了Multisample的Resolve操作。
 9
10     glBindFramebuffer(GL_READ_FRAMEBUFFER,0);
11     glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0);   

  值得注意的是,在绑定了之前申请的FBO,渲染所有需要渲染的物体到其绑定的RenderBuffer之后,需要进行从FBO到default framebuffer的Blit操作,此期间Multisample的Resolve操作由OpenGL为你悄无声息地完成了。



  下面来说道下,FBO渲染到Texture的多重采样方式!

  首先先来看看FBO初始化部分的代码:

 1     GLint iUnits;
 2     glGetIntegerv(GL_MAX_TEXTURE_UNITS,&iUnits);
 3     printf("Max Texutre Units Supported is %d.h\n",iUnits);
 4
 5     glActiveTexture(GL_TEXTURE0);
 6     glGenTextures(1,&m_texID);
 7     glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,m_texID);      //注意与普通Texture的不同,这里绑定的Target是 GL_TEXTURE_2D_MULTISAMPLE,意图已经很明显了吧!
 8
 9     glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,4,GL_RGBA8,m_width,m_height,GL_TRUE);  //分配空间的函数也是调用的Multisample版本,Target依然是GL_TEXTURE_2D_MULTISAMPLE
10
11     glGenRenderbuffers(1,&m_multiSampleDepth);
12     glBindRenderbuffer(GL_RENDERBUFFER,m_multiSampleDepth);
13     glRenderbufferStorageMultisample(GL_RENDERBUFFER,4,GL_DEPTH_COMPONENT,m_width,m_height);  //我们依然需要支持多重采样的Depth Buffer,不然Framebuffer完整性检查会通不过。
14
15     glGenFramebuffers(1,&m_multiSampleFBO);
16     glBindFramebuffer(GL_FRAMEBUFFER,m_multiSampleFBO);
17     glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D_MULTISAMPLE,m_texID,0);  //注意Target依然是GL_TEXTURE_2D_MULTISAMPLE
18     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,m_multiSampleDepth);
19
20     GLenum drawBufs[] = {GL_COLOR_ATTACHMENT0};
21     glDrawBuffers(1, drawBufs);
22
23     GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
24     if( result == GL_FRAMEBUFFER_COMPLETE) {
25         printf("Framebuffer complete!\n");
26     } else {
27         printf("Framebuffer incomplete!\n");
28     }

  

  在上述代码的注释中已经写得很清楚,我们需要支持Multisample的Texture,相关的绑定Target以及内存空间分配函数都有各自的Multisample版本。

  接下来看看渲染部分的代码:(只挑重要的部分)

        //Pass 1:
        glBindFramebuffer(GL_FRAMEBUFFER,m_multiSampleFBO);

        //Select Shader Programs, Setup Matrices, Lights, Materials.

        //Render Objects

        //Pass 2:
        glBindFramebuffer(GL_FRAMEBUFFER,0);

        //Select Shader Programs, Setup Shader Uniforms.

        //Render A Full Screen Quad!

  上面的代码貌似啥内容都没有哈,其实简单的说,分为2个render pass。 第一个Pass,将物体渲染到多重采样过的纹理中。第二个pass,将纹理resolve到defaul Framebuffer,即屏幕上。

  其实在关键在于第二个pass中的resolve过程。贴上代码。这是pass 2的Fragment shader。

 1 #version 400
 2
 3 in vec2 Coord;
 4
 5 layout (location = 0) out vec4 FragColor;
 6
 7 uniform sampler2DMS baseTex;    //注意,此处不再是普通的sampler2D,而是sampler2DMS,专职疑难多重采样问题。
 8
 9 uniform int nMultiSample;      //采样个数,此处传入为4
10
11
12
13 void main(void)
14 {
15     ivec2 texSize = textureSize(baseTex);
16
17     vec4 fTexCol = vec4(0.0);
18
19     if( 0 == nMultiSample )
20     {
21         FragColor = texelFetch(baseTex,ivec2(Coord * texSize),0);
22     }
23     else
24     {
25         for( int i = 0 ; i < nMultiSample ; i++ )
26         {
27             fTexCol += texelFetch(baseTex, ivec2(Coord * texSize), i);  //获取每个采样点的颜色,然后求平均。如果想试其他的resolve方法,It‘s up to you!
28         }
29         FragColor = fTexCol / nMultiSample;
30     }
31 }

  在Fragment shader中,通过一个sampler2DMS 获取纹理中的4个采样点,通过texelFetch内置函数获取采样点颜色,求平局值,作为这个像素的最终值!

  终于写完了!呼~

  

关于支持多重采样的FBO和Texture

时间: 2024-10-25 12:03:53

关于支持多重采样的FBO和Texture的相关文章

OpenGL中的多重采样

抗锯齿处理的最大优点之一就是它能够使多边形的边缘更为平滑,使渲染效果显得更为逼真和自然.点和直线的抗锯齿处理是得到广泛支持的,但遗憾的是,对多边形的平滑处理并没有在所有平台上都得到实现.并且,即使在可以使用GL_POLYGON_SMOOTH的时候,对整个场景进行抗锯齿处理也没有想象中的那么方便.这是因为,抗锯齿处理是基于混合操作的,这就需要从前到后对所有的图元进行排序,这是十分麻烦的. 在OpenGL中还有一个功能,称为多重采样(multisampling),可以用来解决抗锯齿处理中的这个问题.

opengl 反走样 混合 多重采样 blend multisample

1. 反走样         在光栅图形显示器上绘制非水平且非垂直的直线或多边形边界时,或多或少会呈现锯齿状或台阶状外观.这是因为直线.多边形.色彩边界等是连续的,而光栅则是由离散的点组成,在光栅显示设备上表现直线.多边形等,必须在离散位置采样.由于采样不充分重建后造成的信息失真,就叫走样(aliasing).而用于减少或消除这种效果的技术,就称为反走样(antialiasing). 2. OpenGL反走样的实现 OpengL中的反走样采用的是融合的技术,来实现点.线和图形的边沿以及雾和颜色和

Windows下,通过程序设置全屏抗锯齿(多重采样)的方法

这里说的全屏抗锯齿,不是基于着色器的FXAA之类的方式,而是兼容性更好的,基于固定管线的多重采样方式. 先来说一下开发环境,我用的是VC2013+GLEW1.11. 要通过程序设置多重采样,首先需要进入控制面板,确定抗锯齿的设置是“根据应用程序而定” ,当然,这个设置的具体名称,不同的显卡厂商有不同的叫法. 接下来,就是重点了. Windows下要通过程序设置多重采样,必须使用wglChoosePixelFormatARB这个函数.目前网上基本都是自己去获取这个函数的接口地址,其实根本不用这么麻

Chromium网页GPU光栅化原理分析

在前面一篇文章中,我们分析了网页分块的光栅化过程.根据Chromium的启动选项,网页分块有可能使用GPU来执行光栅化操作,也有可能使用CPU来执行光栅化操作.不管是使用GPU,还是CPU,光栅化操作最终都是统一通过调用Skia图形库提供的绘图接口完成的.如果使用GPU来执行光栅化操作,那么当它在调用绘图接口的时候,实际上是在执行相应的OpenGL命令.本文接下来就详细分析GPU光栅化的实现原理. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! 网页分块的

OpenGL入门学习

说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640*480分辨率.16色来做吗?显然是不行的. 本帖的目的是让大家放弃TC的老旧图形接口,让大家接触一些新事物. OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性. 1.与C语言紧密结合. OpenGL命令最初就是用C语言函数来进行描述的,对于学习过C语言的人来讲,OpenGL是容易理解和学习的

OpenGL理解

说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640*480分辨率.16色来做吗?显然是不行的. 本帖的目的是让大家放弃TC的老旧图形接口,让大家接触一些新事物. OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性. 1.与C语言紧密结合. OpenGL命令最初就是用C语言函数来进行描述的,对于学习过C语言的人来讲,OpenGL是容易理解和学习的

back

OpenGL入门学习[五] 今天要讲的是三维变换的内容,课程比较枯燥.主要是因为很多函数在单独使用时都不好描述其效果,我只好在最后举一个比较综合的例子.希望大家能一口气看到底了.只看一次可能不够,如果感觉到迷糊,不妨多看两遍.有疑问可以在下面跟帖提出.我也使用了若干图形,希望可以帮助理解. 在前面绘制几何图形的时候,大家是否觉得我们绘图的范围太狭隘了呢?坐标只能从-1到1,还只能是X轴向右,Y轴向上,Z轴垂直屏幕.这些限制给我们的绘图带来了很多不便. 我们生活在一个三维的世界——如果要观察一个物

【OpenGL】OpenGL初学

转载自:http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640*480分辨率.16色来做吗?显然是不行的. 本帖的目的是让大家放弃TC的老旧图形接口,让大家接触一些新事物. OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性

ue4 4.14的世界设置

渲染设置(Rendering Setting) 本文介绍 ue4 4.14的世界设置 在编辑器最上端点击"设置"(Settings)按钮, 选择"项目设置"(Project Settings)打开"项目设置"面板, 在项目设置面板左边的 "引擎"(Engine)中选择Rendering 打开渲染设置,这些设置被保存在DefaultEngine.ini中 渲染设置中的属性介绍: Mobile Mobile HDR : 是否在手机