• 第二十三课,抗锯齿(Anti Aliasing)


    Anti Aliasingˈæntiˈeliəsɪŋ )反走样

    超采样抗锯齿(Super Sample Anti-aliasing, SSAA)

    使用更高分辨率的帧缓存生成图片,再通过多余的像素来做抗锯齿操作。

    虽然它确实能够解决走样的问题,但是由于这样比平时要绘制更多的片段,它也会带来很大的性能开销。

    在这项技术的基础上也诞生了更为现代的技术,叫做多重采样抗锯齿(Multisample Anti-aliasing, MSAA)

    多重采样抗锯齿(Multisample Anti-aliasing, MSAA)

    MSAA是“多重采样抗锯齿”,可以使画面更加平滑。

    超级采样抗锯齿(Super Sampling Anti-Aliasing)的原理是把当前分辨率成倍提高,然后再把画缩放到当前的显示器上。这样的做法实际上就是在显示尺寸不变的情况提高分辨率,让单个像素变得极小,这样就能够大幅减轻画面的锯齿感了。不过是由于对整个显示画面的放大,因此它消耗的显示资源也是非常大的。不过MSAA是寻找出物体边缘部分的像素,然后对它们进行缩放处理。由于只是物体的外层像素进行缩放处理,忽略掉了不会产生锯齿的内部像素,所以显卡不会像处理SSAA(超级采样抗锯齿)那样需要庞大的计算量,因此MSAA比起SSAA来更有效。

    GLFW中的MSAA

    glfwCreateWindow调用之前提示窗口使用多重采样glfwWindowHint(GLFW_SAMPLES, 4);
    启动glEnable(GL_MULTISAMPLE);开启多重采样(一般情况下默认开启)

    OpenGL离屏MSAA

    缓存

    使用纹理缓存

    在帧缓存绑定的纹理中使用glTexImage2DMultisample,纹理目标是GL_TEXTURE_2D_MULTISAPLE

    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
    glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
    
    • 1
    • 2
    • 3

    它的第二个参数设置的是纹理所拥有的样本个数。如果最后一个参数为GL_TRUE,图像将会对每个纹素使用相同的样本位置以及相同数量的子采样点个数。

    使用glFramebufferTexture2D将多重采样纹理附加到帧缓冲上。

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0);
    
    • 1

    使用多重采样缓冲对象缓存

    我们所要做的只是在指定(当前绑定的)渲染缓冲的内存存储时,将glRenderbufferStorage的调用改为glRenderbufferStorageMultisample就可以了。

    glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
    
    • 1

    将多重采样帧缓存直接渲染到屏幕

    glBlitFramebuffer会将一个用4个屏幕空间坐标所定义的源区域复制到一个同样用4个屏幕空间坐标所定义的目标区域中。
    将离屏帧缓存定义为读缓存,将屏幕定义为渲染缓存。

    glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    
    
    • 1
    • 2
    • 3
    • 4

    函数glBlitFramebuffer

    glBlitFramebuffer(readbuffer(srcX0, srcY0, srcX1, srcY1),drawbuffer(dstX0, dstY0, dstX1, dstY1),mask,filter)
    mask:指示要复制哪些缓冲区的标志的“或”位。允许的标志是GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。
    filter:指定在图像拉伸时应用的插值。必须为GL_NEAREST或GL_LINEAR。

    将多重采样纹理传送为一个普通颜色附件

    没有实际代码。

    自定义抗锯齿算法

    使用Uniform将多重采样纹理导入着色器

    uniform sampler2DMS screenTextureMS;
    
    • 1

    使用texelFetch获取每个子样本的颜色值

    vec4 colorSample = texelFetch(screenTextureMS, TexCoords, 3);  // 第4个子样本
    
    • 1

    QT+OpenGL中的MSAA

    内置方法

    在这里插入图片描述
    使用抗锯齿

    GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent)
    {
        QSurfaceFormat formate;
        formate.setSamples(4);//采样数
        setFormat(formate);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    使用后的问题:glReadPixels无法获取到物体的模板值。(怎么解决,尚且不知)。

    离屏方法

    引自:https://www.liangzl.com/get-article-detail-230476.html

    想要实现离屏的MSAA,我们需要添加两个QOpenGLFrameBufferObject实例;其中一个用于多重采样, 一个多重采样的图像包含比普通图像更多的信息 ,所以此时我们的另外一个QOpenGLFrameBufferObject 实例就需要实现降采样;

    那么首先我们创建两个FBO,并分别设置其采样值

    //MultiSampling set to 4 now
    		QOpenGLFramebufferObjectFormat muliSampleFormat;
           	muliSampleFormat.setAttachment (QOpenGLFramebufferObject::CombinedDepthStencil);
            muliSampleFormat.setMipmap(true);
            muliSampleFormat.setSamples(4);
            muliSampleFormat.setTextureTarget(GL_TEXTURE_2D);
            muliSampleFormat.setInternalTextureFormat(GL_RGBA32F_ARB);
    
            //fbo=new QOpenGLFramebufferObject(this->width(),this->height(),QOpenGLFramebufferObject::Depth);
            fbo=new QOpenGLFramebufferObject(this->width(),this->height(),muliSampleFormat);
    
            QOpenGLFramebufferObjectFormat downSampledFormat;
            downSampledFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
            downSampledFormat.setMipmap(true);
            downSampledFormat.setTextureTarget(GL_TEXTURE_2D);
            downSampledFormat.setInternalTextureFormat(GL_RGBA32F_ARB);
    
            renderfbo=new QOpenGLFramebufferObject(this->width(),this->height(),downSampledFormat);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    然后在执行渲染操作的时候,首先绑定多重采样FBO,将内容绘制到多重采样FBO中,然后解绑多重采样FBO。接着绑定降采样FBO,然后使用 QOpenGLFramebufferObject::blitFramebuffer方法,实现位块传送,此时解绑降采样FBo。然后从降采样的FBO中获取textureid,并进行渲染;

    void MyGLWidget::paintGL()
    {
        if(fbo!=nullptr)
        {
            bool result = fbo->bind();
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
          
            //在此进行物体的渲染
    
    
    
            if(result)
            {
                fbo->release();
                renderfbo->bind();
                QOpenGLFramebufferObject::blitFramebuffer(renderfbo,fbo,GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT| GL_STENCIL_BUFFER_BIT,GL_NEAREST);
                renderfbo->release();
                GLuint textureid=renderfbo->texture();
    
                m_program->bind();
                {
                    glActiveTexture(GL_TEXTURE0);
                    glBindTexture(GL_TEXTURE_2D, textureid);
                    glUniform1i(m_program->uniformLocation("screenTexture"), 0);
                    m_vao->bind();
                    glDrawArrays(GL_TRIANGLES, 0, 6);
                    m_vao->release();
    
                }
                m_program->release();
            }
    
        }
       
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
  • 相关阅读:
    springboot 调用第三方接口的方式(一)使用RestTemplate方法
    nginx简单学习笔记
    第9章 无监督学习
    1024程序员节:庆祝编程的魅力
    B. Box
    Qt基础教程:QAbstractButton
    十分钟就能写个xxl-job插件
    Nosql数据库服务之redis
    SparkSQL DataFrame的介绍及创建
    深入浅出 JavaScript 中的 this
  • 原文地址:https://blog.csdn.net/weixin_44518102/article/details/126062565