前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >23.opengl高级-抗锯齿

23.opengl高级-抗锯齿

作者头像
公号sumsmile
发布2020-07-17 09:46:52
2.8K0
发布2020-07-17 09:46:52
举报

这两天有点疲惫,这一章节的代码没有run起来看效果,重点理解锯齿现象和抗锯齿的实现

一、锯齿生成原理

锯齿原理-参考知乎fengliancanxue

参考上图,几何图形是连续的坐标连接实现的,实际屏幕上的像素是离散化的点,分辨率越低的屏幕离散越剧烈,在图形的边缘必然会产生锯齿。

抗锯齿有两种常见的方案:1)超采样抗锯齿(Super Sample Anti-aliasing, SSAA);2)多重采样抗锯齿(Multisample Anti-aliasing, MSAA),MSAA借鉴了SSAA背后的理论。

SSAA背后的理论说明,比如400 x 400的图片,采样成100 x 100,那就是缩放成原图的1/4,那么就可以用平均值的方式从相邻的4个像素采样生成100 x100中的一个新像素。SSAA用高分辨率图来降低锯齿效果较好,但是牺牲了内存性能。

MSAA的方式是在内存中将一个采样点拓展成4个子采样点,4个子采样点不一定都在三角形中,计算包含在三角形内的子采样点的比例,再乘以原采样颜色,即得到该边缘点应该渲染的颜色。再简单点,包含在三角形中的子采样点越少,该像素的实际像素越淡

4个子采样点

边缘像素的处理

暂时先理解这么多,到用时再回头来深入研究

二、Opengl中的MSAA
2.1 默认窗口的话,2行代码实现
代码语言:javascript
复制
glfwWindowHint(GLFW_SAMPLES, 4);
glEnable(GL_MULTISAMPLE);

无抗锯齿

锯齿放大

抗锯齿

2.2 离屏MSAA

使用glTexImage2DMultisample来替代glTexImage2D,它的纹理目标是GL_TEXTURE_2D_MULTISAPLE。

代码语言:javascript
复制
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);

我们使用glFramebufferTexture2D将多重采样纹理附加到帧缓冲上,但这里纹理类型使用的是GL_TEXTURE_2D_MULTISAMPLE。

代码语言:javascript
复制
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0);

和纹理类似,创建一个多重采样渲染缓冲对象并不难。我们所要做的只是在指定(当前绑定的)渲染缓冲的内存存储时,将glRenderbufferStorage的调用改为glRenderbufferStorageMultisample就可以了。

代码语言:javascript
复制
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);

因为多重采样缓冲有一点特别,我们不能直接将它们的缓冲图像用于其他运算,比如在着色器中对它们进行采样。

一个多重采样的图像包含比普通图像更多的信息,我们所要做的是缩小或者还原(Resolve)图像。多重采样帧缓冲的还原通常是通过glBlitFramebuffer来完成,它能够将一个帧缓冲中的某个区域复制到另一个帧缓冲中,并且将多重采样缓冲还原。

代码语言:javascript
复制
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);

你可以看到,如果将多重采样与离屏渲染结合起来,我们需要自己负责一些额外的细节。但所有的这些细节都是值得额外的努力的,因为多重采样能够显著提升场景的视觉质量。当然,要注意,如果使用的采样点非常多,启用多重采样会显著降低程序的性能。在本节写作时,通常采用的是4采样点的MSAA。

三、自定义抗锯齿算法

将一个多重采样的纹理图像不进行还原直接传入着色器也是可行的。GLSL提供了这样的选项,让我们能够对纹理图像的每个子样本进行采样,所以我们可以创建我们自己的抗锯齿算法。在大型的图形应用中通常都会这么做。

要想获取每个子样本的颜色值,你需要将纹理uniform采样器设置为sampler2DMS,而不是平常使用的sampler2D:

代码语言:javascript
复制
uniform sampler2DMS screenTextureMS;

使用texelFetch函数就能够获取每个子样本的颜色值了:

代码语言:javascript
复制
vec4 colorSample = texelFetch(screenTextureMS, TexCoords, 3);  // 第4个子样本

可以自己设计权重,计算输出颜色值 我们不会深入探究自定义抗锯齿技术的细节,这里仅仅是给你一点启发。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、锯齿生成原理
  • 二、Opengl中的MSAA
    • 2.1 默认窗口的话,2行代码实现
      • 2.2 离屏MSAA
      • 三、自定义抗锯齿算法
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档