Anti Aliasing(ˈænti
,ˈeliəsɪŋ
)反走样
使用更高分辨率的帧缓存生成图片,再通过多余的像素来做抗锯齿操作。
虽然它确实能够解决走样的问题,但是由于这样比平时要绘制更多的片段,它也会带来很大的性能开销。
在这项技术的基础上也诞生了更为现代的技术,叫做多重采样抗锯齿(Multisample Anti-aliasing, MSAA)
MSAA是“多重采样抗锯齿”,可以使画面更加平滑。
超级采样抗锯齿(Super Sampling Anti-Aliasing)的原理是把当前分辨率成倍提高,然后再把画缩放到当前的显示器上。这样的做法实际上就是在显示尺寸不变的情况提高分辨率,让单个像素变得极小,这样就能够大幅减轻画面的锯齿感了。不过是由于对整个显示画面的放大,因此它消耗的显示资源也是非常大的。不过MSAA是寻找出物体边缘部分的像素,然后对它们进行缩放处理。由于只是物体的外层像素进行缩放处理,忽略掉了不会产生锯齿的内部像素,所以显卡不会像处理SSAA(超级采样抗锯齿)那样需要庞大的计算量,因此MSAA比起SSAA来更有效。
在glfwCreateWindow
调用之前提示窗口使用多重采样glfwWindowHint(GLFW_SAMPLES, 4);
启动glEnable(GL_MULTISAMPLE);
开启多重采样(一般情况下默认开启)
在帧缓存绑定的纹理中使用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);
它的第二个参数设置的是纹理所拥有的样本个数。如果最后一个参数为GL_TRUE,图像将会对每个纹素使用相同的样本位置以及相同数量的子采样点个数。
使用glFramebufferTexture2D
将多重采样纹理附加到帧缓冲上。
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0);
我们所要做的只是在指定(当前绑定的)渲染缓冲的内存存储时,将glRenderbufferStorage
的调用改为glRenderbufferStorageMultisample
就可以了。
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
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);
函数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;
使用texelFetch
获取每个子样本的颜色值
vec4 colorSample = texelFetch(screenTextureMS, TexCoords, 3); // 第4个子样本
使用抗锯齿
GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent)
{
QSurfaceFormat formate;
formate.setSamples(4);//采样数
setFormat(formate);
}
使用后的问题: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);
然后在执行渲染操作的时候,首先绑定多重采样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();
}
}
}