1. 反走样
在计算机图形学中,在屏幕上显示对象时,可能会出现许多的“锯齿”,这些锯齿是由顶点数据像素化之后成为片段的方式所引起的,由于将数学意义上的坐标转换到物理的显示器硬件上进行显示,显示器是有一个个像素点构成的,并不能实现数学意义上的“无限小”的描述。关于产生锯齿的更详细的介绍可以参考OpenGL学习脚印: 反走样初步(Anti-aliasing basic)

为了消除“锯齿”,图形工作者提出了许多抗锯齿的算法(也称为反走样[Anti-aliasing]算法),本文主要介绍OpenGL中提到的一种反走样方法——多重采样(Multisample antialiasing简称 MSAA)。接触到这一主题时,查阅了很多资料,发现网络上许多内容都大同小异,很多内容并没有参考价值。整体的思路说清楚了,但是一旦涉及到某一项技术,最难的往往是技术中的细节部分。本文记录我个人在理解MSAA时候比较困惑的点,在理解之后记录下来。

2. Supersampling
在理解MSAA之前,有必要先理解一下什么是SuperSampling (字面翻译是超采样,简称是SSAA),超采样就是加大采样的点,提供比屏幕分辨率更多的采样点。是渲染的时候按照显示器分辨率的若干倍来渲染,例如显示器1024x768,那么SSAA 4X就是4096x3072。

上图是OpenGL决定一个像素颜色采用的算法,如果红色的采样点(像素中心位置)落在三角形区域,那么这个像素就被认为属于三角形,从而会着色成为三角形的颜色。但是边缘部分的像素并没有“完全属于”三角形,那么这些像素的颜色应该是某种介于边缘多种颜色的“过渡色”比较合理一点。
SSAA的想法比较简单,就是扩大采样点,生成一些次像素级别的采样点(sub-pixel)。有点类似股份公司的感觉,把像素理解成为一家公司,那么这家公司归属谁呢?在中心区域,由于完全被三角形区域所包含,那么属于三角形没有什么争议,但是边缘部分的像素由于并没有完全被三角形占据,那么它的所有权问题就应该是多个股东决议的结果,根据大家股份占用的大小来中和最后的结果。

在像素中如何添加新的次像素级别的采样点,方法很多。不同的采样点设计方式最终对场景渲染的结果也不同。以下是一些采样点的选择方式:

得到次级像素的采样点之后,把这个场景渲染到一个更高分辨率的缓冲区A中,然后再从A缓冲区中采样出和屏幕分辨率一样的像素,像素的颜色使用A缓冲区中的像素颜色插值得到。整体的思路如下图所示:

上图中使用4个采样点,如果不使用SSAA技术,那么最终屏幕上这个像素的颜色是中心位置的黄色,使用了SSAA之后,这个像素的颜色是淡淡的棕黄色,这个颜色综合了像素中其他的颜色值计算而来的。(图示中使用的是简单的求平均值的方法,在实际中可能会有其他的算法来计算,但是整体思路还是一样的)

在SSAA方法中,有一个需要注意的地方是:所有的次级采样点和未使用SSAA中采样点的地位是一样的,假设有片元shader需要在每一个像素上运行,那么SSAA中片元shader也会在每一个次级像素上运行。理解这一点非常的关键,它是SSAA和MSAA最重要的一个区别。

SSAA的缺点:通过上面的分析可以知道SSAA需要占用更大的显存空间,它需要更大缓冲区,采用4x、8x、16x那么使用的空间是未开启SSAA的4倍,8倍和16倍。另外SSAA需要每一个shader在所有次级片元上都同样的运行一遍,这也是一笔可观的计算开销,会显著地降低FPS。

3. MSAA
有了SSAA的基础,那么理解多重采样(MSAA)就简单很多了。MSAA中增加采样的方式和SSAA是一样的,MSAA同样也需要一个分辨率更高的缓冲区(假设命名是Anti-Buffer),但是MSAA并不是像SSAA一样把次级采样点当成类似未开启反走样中采样点同等地位来对待,它采用另一种方式。
示意图如下:

图示中两个三角形的图元都包含了像素的采样点(圆形位置),4个叉代表着该像素的4个子采样点。在开启MSAA之后的过程如下:
首先由于屏幕背景清空色是白色,那么Anti-Buffer中的每一个子采样点的颜色都设置成了白色,
假设蓝色的三角形首先绘制,由于它包含像素的采样点,因此在跑了一次shader之后,左下角的这个2个子采样点在Anti-Buffer缓冲区的值被蓝色填充,然后开始绘制黄色三角形,由于它也包含像素的采样点,因此也会跑一次shader,假设计算的结果是黄色。由于右边的采样点被它包含,因此被设置成黄色,最终这个像素对应在Anti-Buffer缓冲区中4个子采样点的颜色是白色、黄色、蓝色、蓝色。最终的颜色由这4个颜色计算平均得到。

也就是说:MSAA每一个像素上shader只运行一次,运行的结果会复制到每一个包含了子采样点的缓冲区中。而不是像SSAA那样每一个子采样点都运行一次shader。大大减少了shader的运行次数。

4. MSAA在OpenGL中的使用
网络上许多关于MSAA在OpenGL中的使用方式都没有说的很清楚,这里就介绍一下OpenGL中的MSAA。

OpenGL中有很多状态变量,默认情况下基本都是关闭的(比如光照计算、混合计算、深度测试等等),但是只有两个状态默认是开启的,MSAA就是其中之一(另一个是Dither),要使用OpenGL提供的MSAA,需要申请一个可以进行超采样的缓冲区(也就是我们上文说的Anti-Buffer),申请的方式和窗口系统有关,在GLUT中申请的方式很简单,只需要添加一个枚举值的变量GLUT_MULTISAMPLE即可:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH |GLUT_RGBA | GLUT_MULTISAMPLE);

添加缓冲区之后,开启多重采样即可(默认是开启的可以不用显式设置),开启方式:glEnable(GL_MULTISAMPLE);

使用方式就是这么简单,另外在OpenGL中还有一些多重采样控制的参数需要设置,相关的API如下:

开启多重采样覆盖率的设置
在MSAA介绍部分,我们列举的例子中,说到了最后的颜色由白色、黄色、蓝色、蓝色。这4个颜色计算平均得到。这里的描述是不完全准确,OpenGL默认情况下是会直接取4个颜色的平均值,但是也可以添加更多的控制。

默认计算算法((color1+color2+color3+...+colorn) / n),需要注意这时候color的alpha值是不参与计算的。

如果进行下面的设置,那么计算算法会改变,

4.1. glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
设置之后alpha值参与计算

由于多重采样的实现方式很多,OpenGL也没有规定硬件应该怎么实现多重采样,都是交给硬件自身处理。因此这里我们描述一种可能的多重采样的处理过程:
当我们使用4x,8x等MSAA时,OpenGL会为每一个像素分配一个掩码值,这个掩码值的位数是由子采样的点数决定的,也就是说4x是分配4位,8x是分配8位。分配完成之后,这些位记录了一个子采样点是否被其他几何图元覆盖到了,以3中的情况为例,由于那4个采样点有3个被覆盖到了,因此那个像素中的Coverage掩码是 0 1 1 1

A B C D ————> 4个采样掩码位

0 1 1 1 ————–>覆盖掩码值

白色 蓝色 蓝色 黄色 ——>MSAA采样缓冲区值

然后再计算平均值的时候考虑到某一个掩码是0,那么该子采样点的颜色就不参与最后的运算了。

上面说的是正常的处理过程,一旦我们设置了glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE),那么这个掩码就要开始运算了:设置之后,OpenGL会根据MSAA缓冲区中颜色值的Alpha成分,生成一个掩码值,并与这个原来的掩码进行按位与的运算。(alpha值是一个浮点数的值,怎么进行按位与的运算呢?原来OpenGL可以通过映射,将某一范围内的值映射成一个整数),生成一个新的掩码值。具体来说是:
一个fragment的Alpha值在0~1间,它对应着一个值。还是以4XMSAA为例,这个值也是xxxx的形式,Alpha为0对应了0000,alpha为1对应了1111,至于中间的值的对应关系,OpenGL是交由显卡制造商决定的——其实一般就是类似[0~0.249 -> 0000, 0.25~0.499 -> 0001, 0.5~0.749 -> 0011, 0.75~0.99-> 0111]这样(在D3D11中,就可以自定义这个值)。这个值与与coverage mask作一次逻辑按位与操作获得新的coverage mask。

4.2 glEnable(GL_SAMPLE_ALPHA_TO_ONE);
设置多重采样中每一个子采样点的颜色alpha成分是1。

4.3 . glSampleCoverage
开启自定义设置,需要2个函数调用
glEnable(GL_SAMPLE_COVERAGE)
glSampleCoverage
这里面glSampleCoverage的函数原型如下:

void glSampleCoverage(  GLclampf    value,GLboolean   invert);

第一个参数是 value,表示掩码值
第二个参数是 invert,表示是否翻转计算

第一次看到这个接口API时,发现是一个float的value值,OpenGL的spec文档中一直提到要做按位的与运算,我就一脸懵逼了,按位运算不是整型才有的运算操作吗?是不是说这个value会被cast成一个整型,既然要cast成一个整型为什么不设置参数类型就是整型呢?

事实上是这样的:这个浮点数的值会被映射成一个整型数,和之前alpha_to_coverage类似

glSampleCoverage的效果和 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);有点类似,都是设置掩码和原来像素的coverage掩码作按位与的运算,不同之处是后者使用颜色成分的alpha值运算。而这个函数是自己指定一个值,这个值是value映射后的整型值。第二个参数invert是对这个value映射后的整型值作按位取反操作。然后再与像素的coverage掩码作运算。

以上是所有OpenGL中和MSAA反走样相关的内容。反走样是一个十分庞大的主题,读者也可以通过FBO自己实现反走样的算法,关于在FBO中作反走样,可以阅读参考资料中的内容。

5. 参考资料
1. OpenGL学习脚印: 反走样初步(Anti-aliasing basic)
2. 抗锯齿
3. Supersampling
4. Multisample Anti-Aliasing
5. Rasterization Rules
6. 乱弹纪录II:Alpha To Coverage
————————————————
版权声明:本文为CSDN博主「csxiaoshui」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/csxiaoshui/article/details/78932603

反走样和OpenGL多重采样相关推荐

  1. 计算机图形学【GAMES-101】2、光栅化(反走样、傅里叶变换、卷积)

    快速跳转: 1.矩阵变换原理Transform(旋转.位移.缩放.正交投影.透视投影) 2.光栅化(反走样.傅里叶变换.卷积) 3.着色计算(深度缓存.着色模型.着色频率) 4.纹理映射(重心坐标插值 ...

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

    1. 反走样         在光栅图形显示器上绘制非水平且非垂直的直线或多边形边界时,或多或少会呈现锯齿状或台阶状外观.这是因为直线.多边形.色彩边界等是连续的,而光栅则是由离散的点组成,在光栅显示 ...

  3. NeHe OpenGL第四十六课:全屏反走样

    NeHe OpenGL第四十六课:全屏反走样 全屏反走样 当今显卡的强大功能,你几乎什么都不用做,只需要在创建窗口的时候该一个数据.看看吧,驱动程序为你做完了一切.   在图形的绘制中,直线的走样是非 ...

  4. 【转】OpenGL反走样

    反走样:        在光栅图形显示器上绘制非水平且非垂直的直线或多边形边界时,或多或少会呈现锯齿状或台阶状外观.这是因为直线.多边形.色彩边界等是连续的,而光栅则是由离散的点组成,在光栅显示设备上 ...

  5. OPENGL简介---反走样

    由于计算机以离散点生成图形,生成图形必然与真实景物存在差距,这种差距表现为:直线或光滑曲面的锯齿.花纹失去原有色彩形状.细小物体在画面的消失等.统统叫做走样(aliasing).反走样可以减少这种情况 ...

  6. OpenGL MSAA多重采样抗锯齿的实例

    OpenGL MSAA多重采样抗锯齿 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <glad/glad.h> #include & ...

  7. 图形学中的贴图采样、走样与反走样等

    图形学中的贴图采样.走样与反走样等 https://blog.csdn.net/bugrunner/article/details/8829438 计算机图形学中不可避免的会涉及到图像分析与处理的相关 ...

  8. 图形学中的贴图采样、走样与反走样等,图形学走样

    文章转自:http://www.bkjia.com/ASPjc/912364.html 版权归原作者! 计算机图形学中不可避免的会涉及到图像分析与处理的相关知识,前些时间也重温了下常用到的采样.重建以 ...

  9. 【OpenGL】多重采样案例MSAA

    示例图暂缺(目前运行exe失败,后期补充) 本文比较难,个人来说还不是完全弄懂. #version 150 // hdr_bloom.vs // outputs MVP transformed pos ...

最新文章

  1. “接口”的定义及其与“抽象类”的区别
  2. 皮一皮:考试了,全国统一舔狗学校招生考试!
  3. [Unity3d]u3d中定时器的使用
  4. 安装centos7失败认不到硬盘_CentOS7 用U盘安装卡住无法进入安装界面解决方案
  5. java 时间转中文_使用JScript把时间转成中文
  6. vscode 注释插件
  7. markdown编辑软件Ulysses 24.5 for Mac
  8. 使用GameKit实现IOS设备之间的蓝牙通信
  9. 电脑自带office查看攻略
  10. c51单片机之数码管显示(共阳极数码管)
  11. 3d打开无法下载star.php,下载的3dmax模型打开失败的原因及解决方法
  12. 计算机如何远程控制对方手机,如何远程控制别人的电脑【图解】
  13. iOS 程序员、架构师、技术经理、技术总监和CTO有啥区别?
  14. 5分钟python爬虫案例,手把手教爬取国内外最新疫情历史数据
  15. 【Python】新华字典(bushi
  16. 逢七过,逢七坐,逢七出列。。。 。。。各种叫法都有
  17. 2021-03-30
  18. 独享云虚拟主机、共享云虚拟主机、云服务器 ECS 区别
  19. EXPDP 指定排除某些表
  20. ue4 无效模拟选项:形体被设置为模拟物理,但启用碰撞不兼容

热门文章

  1. 内建模块_月隐学python第14课
  2. linux ftp 553,修复使用vsftp出错553 Could not create file的有效方法
  3. 中震弹性计算_众值烈度、中震烈度、大震烈度及三水准二阶段
  4. java对象转json jackson_使用Jackson将Java对象转换为JSON
  5. java简述垃圾回收原理及算法_Java垃圾回收原理和算法
  6. java怎么输出9 99的形式_java如何输出99乘法表
  7. P4390 [BOI2007]Mokia 摩基亚 (CDQ解决三维偏序问题)
  8. SQL server 统计分组经计
  9. 牛客练习赛46 B 华华送奕奕小礼物 (预处理前缀和,二分)
  10. 垒骰子|2015年蓝桥杯B组题解析第九题-fishers