mirror of
https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git
synced 2025-08-23 04:35:28 +08:00
fixed some translation errors and add some annotations
This commit is contained in:
@@ -4,67 +4,69 @@
|
|||||||
---|---
|
---|---
|
||||||
作者 | JoeyDeVries
|
作者 | JoeyDeVries
|
||||||
翻译 | [Django](http://bullteacher.com/)
|
翻译 | [Django](http://bullteacher.com/)
|
||||||
校对 | [Geequlim](http://geequlim.com)
|
校对 | [Geequlim](http://geequlim.com),[KenLee](https://hellokenlee.github.io/)
|
||||||
|
|
||||||
在你的渲染大冒险中,你可能会遇到模型边缘有锯齿的问题。**锯齿边(Jagged Edge)**出现的原因是由顶点数据像素化之后成为片段的方式所引起的。下面是一个简单的立方体,它体现了锯齿边的效果:
|
在你的渲染大冒险中,你可能会遇到模型边缘有锯齿的问题。**锯齿边缘(Jagged Edge)**出现的原因是由顶点数据光栅化成为片元(fragment)的方式所引起的。举个例子,我们随手绘制一个简单的正方体就已经能很清楚地看到锯齿边缘的效果:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
也许不是立即可见的,如果你更近的看看立方体的边,你就会发现锯齿了。如果我们放大就会看到下面的情境:
|
尽管可能不会被立刻察觉到,如果你更近的看看立方体的边,你就会发现锯齿状的图案。如果我们放大就会看到下面的情境:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
这当然不是我们在最终版本的应用里想要的效果。这个效果,很明显能看到边是由像素所构成的,这种现象叫做**走样(Aliasing)**。有很多技术能够减少走样,产生更平滑的边缘,这些技术叫做**抗锯齿技术**(Anti-aliasing,也被称为反走样技术)。
|
这当然不是我们在实际应用中想要的效果。这个效果,我们很明显能看到边缘像素的形态,这种现象被称之为**走样(Aliasing)**。有很多技术能够减少走样现象,产生更平滑的边缘,这些技术叫做**抗锯齿技术**(Anti-aliasing,也被称为反走样技术)。
|
||||||
|
|
||||||
首先,我们有一个叫做**超级采样抗锯齿技术(Super Sample Anti-aliasing, SSAA)**,它暂时使用一个更高的解析度(以超级采样方式)来渲染场景,当视频输出在帧缓冲中被更新时,解析度便降回原来的普通解析度。这个额外的解析度被用来防止锯齿边。虽然它确实为我们提供了一种解决走样问题的方案,但却由于必须绘制比平时更多的片段而降低了性能。所以这个技术只流行了一段时间。
|
最开始我们有一个叫做**超采样抗锯齿技术(Super Sample Anti-aliasing, SSAA)**,它暂时使用一个更高的分辨率(以超采样方式)来渲染场景,当输出图像在帧缓冲中被更新时,图像的分辨率会被下采样(down sample)回原来的分辨率。它使用额外的分辨率来防止锯齿边缘。虽然它确实为我们提供了一种解决走样问题的方案,但却由于必须绘制比平时更多的片段而降低了性能。所以这个技术只流行了一段时间。
|
||||||
|
|
||||||
这个技术的基础上诞生了更为现代的技术,叫做**多采样抗锯齿(Multisample Anti-aliasing)**或叫MSAA,虽然它借用了SSAA的理念,但却以更加高效的方式实现了它。这节教程我们会展开讨论这个MSAA技术,它是OpenGL内建的。
|
这个技术的基础上诞生了更为现代的技术,叫做**多采样抗锯齿(Multisample Anti-aliasing)**或叫**MSAA**,虽然它借用了SSAA的理念,但却以更加高效的方式实现了它。这节教程我们会展开讨论这个OpenGL内建的MSAA技术。
|
||||||
|
|
||||||
## 多重采样
|
## 多重采样
|
||||||
|
|
||||||
为了理解什么是多重采样(Multisampling),以及它是如何解决锯齿问题的,我们先要更深入了解一个OpenGL光栅化的工作方式。
|
为了理解什么是多重采样(Multisampling),以及它是如何解决锯齿问题的,我们先要更深入了解一下OpenGL光栅化的工作方式。
|
||||||
|
|
||||||
光栅化是你的最终的经处理的顶点和片段着色器之间的所有算法和处理的集合。光栅化将属于一个基本图形的所有顶点转化为一系列片段。顶点坐标理论上可以含有任何坐标,但片段却不是这样,这是因为它们与你的窗口的解析度有关。几乎永远都不会有顶点坐标和片段的一对一映射,所以光栅化必须以某种方式决定每个特定顶点最终结束于哪个片段/屏幕坐标上。
|
光栅化表示在我们输出的顶点(Vertices)和片元着色器(fragment shader)中间的所有算法和处理过程的集合(译者注: 在OpenGL中,光栅化步骤在几何着色器后,片元着色器前)。光栅化将属于一个基本图形的所有顶点转化为一系列片元。顶点坐标理论上可以是任意值,但片元却不是这样,这是因为它们受你的窗口的分辨率限制。几乎永远都不会有顶点坐标和片元的一对一映射,所以光栅化必须以某种方式决定每个顶点最终位于哪个片元/屏幕坐标上。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
这里我们看到一个屏幕像素网格,每个像素中心包含一个采样点(sample point),它被用来决定一个像素是否被三角形所覆盖。红色的采样点如果被三角形覆盖,那么就会为这个被覆盖像(屏幕)素生成一个片段。即使三角形覆盖了部分屏幕像素,但是采样点没被覆盖,这个像素仍然不会受到任何片段着色器影响到。
|
这里我们看到一个屏幕像素网格,每个像素中心包含一个采样点(sample point),它被用来决定一个像素是否被三角形所覆盖。红色的采样点表示该点被三角形所覆盖,片元着色器会给该屏幕像素着色。不过即使三角形覆盖了某一个屏幕像素的一部分,但是中心的采样点没被覆盖到,这个像素仍然不会受到片段着色器的影响。
|
||||||
|
|
||||||
你可能已经明白走样的原因来自何处了。三角形渲染后的版本最后在你的屏幕上是这样的:
|
你可能现在已经明白走样的原因是什么了。上述三角形渲染后在你的屏幕上会是这样的:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
由于屏幕像素总量的限制,有些边上的像素能被渲染出来,而有些则不会。结果就是我们渲染出的基本图形的非光滑边缘产生了上图的锯齿边。
|
由于屏幕像素总量的限制,有些边上的像素能被渲染出来,而有些则不会。结果就是我们渲染出的基本图形的边缘产生了上图的锯齿。
|
||||||
|
|
||||||
多采样所做的正是不再使用单一采样点来决定三角形的覆盖范围,而是采用多个采样点。我们不再使用每个像素中心的采样点,取而代之的是4个子样本(subsample),用它们来决定像素的覆盖率。这意味着颜色缓冲的大小也由于每个像素的子样本的增加而增加了。
|
多采样所做的正是不再使用单一采样点来决定三角形的覆盖范围,而是采用多个采样点(这大概就是它名字的由来)。我们不再使用每个像素中心的采样点,取而代之的是4个子采样(subsample),用它们来决定像素是否被覆盖。这意味着颜色缓冲的大小也由于每个像素的子样本的增加而增加了。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
左侧的图显示了我们普通决定一个三角形的覆盖范围的方式。这个像素并不会运行一个片段着色器(这就仍保持空白),因为它的采样点没有被三角形所覆盖。右边的图展示了多采样的版本,每个像素包含4个采样点。这里我们可以看到只有2个采样点被三角形覆盖。
|
上图的左侧显示了我们普通决定一个三角形是否覆盖屏幕像素的方式(译者注: 中心点,单采样)。这个像素并不会被一个片元着色器着色(因此它保持空白),因为它的采样点没有被三角形所覆盖。右边示了多采样的版本,每个像素包含4个采样点。这里我们可以看到只有2个采样点被三角形覆盖。
|
||||||
|
|
||||||
!!! Important
|
!!! Important
|
||||||
|
|
||||||
采样点的数量是任意的,更多的采样点能带来更精确的覆盖率。
|
采样点的数量是任意的,更多的采样点能带来更精确的覆盖率。
|
||||||
|
|
||||||
多采样开始变得有趣了。2个子样本被三角覆盖,下一步是决定这个像素的颜色。我们原来猜测,我们会为每个被覆盖的子样本运行片段着色器,然后对每个像素的子样本的颜色进行平均化。例子的那种情况,我们在插值的顶点数据的每个子样本上运行片段着色器,然后将这些采样点的最终颜色储存起来。幸好,它不是这么运作的,因为这等于说我们必须运行更多的片段着色器,会明显降低性能。
|
从这儿开始我们的多重采样变得有趣起来了。我们知道了只有2个子采样被三角覆盖,下一步就是决定这个像素的颜色。我们可以猜测一下,我们会为每个被覆盖的子采样运行片元着色器,然后对每个像素的所有子采样的颜色进行平均化。在这种情况下,我们需要为每一个被插值后的顶点数据的每一个子采样运行两次两次片元着色器,然后把采样点的颜色储存起来。幸好,它不是这么运作的,因为这等于说我们必须运行更多的片段着色器,会明显降低性能。
|
||||||
|
|
||||||
MSAA的真正工作方式是,每个像素只运行一次片段着色器,无论多少子样本被三角形所覆盖。片段着色器运行着插值到像素中心的顶点数据,最后颜色被储存近每个被覆盖的子样本中,每个像素的所有颜色接着将平均化,每个像素最终有了一个唯一颜色。在前面的图片中4个样本中只有2个被覆盖,像素的颜色将以三角形的颜色进行平均化,颜色同时也被储存到其他2个采样点,最后生成的是一种浅蓝色。
|
MSAA的真正工作方式是,每个像素只运行一次片元着色器,无论该像素有多少子样本被三角形所覆盖。片元着色器接受的顶点数据是被插值到每一个像素的**中心**坐标,而其着色的颜色会被每个被三角形覆盖的子采样储存。一旦一个我们绘制的基本图形的子采样颜色缓冲被填满了,每个像素对应的所有颜色将会被平均化,这使得每个像素最终有了一个唯一颜色。比如在前面的图片中4个子采样中只有2个被三角形覆盖,像素的颜色事实上是一个均值,该均值由三角形的颜色和其他2个子采样的颜色(aka. 背景色)平均化而成,最后该像素被着色为一种浅蓝色。
|
||||||
|
|
||||||
结果是,颜色缓冲中所有基本图形的边都生成了更加平滑的样式。让我们看看当再次决定前面的三角形覆盖范围时多样本看起来是这样的:
|
结果是,颜色缓冲中所有基本图形的边变得更加平滑了。让我们看看多重采样对前面的一个三角形来说是怎样做的:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
这里每个像素包含着4个子样本(不相关的已被隐藏)蓝色的子样本是被三角形覆盖了的,灰色的没有被覆盖。三角形内部区域中的所有像素都会运行一次片段着色器,它输出的颜色被储存到所有4个子样本中。三角形的边缘并不是所有的子样本都会被覆盖,所以片段着色器的结果仅储存在部分子样本中。根据被覆盖子样本的数量,最终的像素颜色由三角形颜色和其他子样本所储存的颜色所决定。
|
这里每个像素包含着4个子采样(不相关采样点的没有被标注出来)蓝色的子采样是被三角形覆盖了的,灰色的则没有被覆盖。三角形内部区域中的所有像素都会运行一次片元着色器,它输出的颜色由4个子采样决定。三角形的边缘并不是所有的子采样都会被覆盖,所以片段着色器的结果仅由部分的子采样决定。根据被覆盖子采样的数量,最终的像素颜色由三角形颜色和其他子采样所储存的颜色所决定。(译者注: 其实有点类似于Blending的原理。)
|
||||||
|
|
||||||
大致上来说,如果更多的采样点被覆盖,那么像素的颜色就会更接近于三角形。如果我们用早期使用的三角形的颜色填充像素,我们会获得这样的结果:
|
大致上来说,如果更多的采样点被覆盖,那么像素的颜色就会更接近于三角形。如果我们用这种方去给我们前面的三角形的填充像素颜色,我们会获得这样的结果:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
对于每个像素来说,被三角形覆盖的子样本越少,像素受到三角形的颜色的影响也越少。现在三角形的硬边被比实际颜色浅一些的颜色所包围,因此观察者从远处看上去就比较平滑了。
|
对于每个像素来说,被三角形覆盖的子采样越少,像素受到三角形的颜色的影响也越少。现在原本三角形不平滑的边被比实际颜色浅一些的颜色像素所包围,因此观察者从远处看上去就比较平滑了。
|
||||||
|
|
||||||
不仅颜色值被多采样影响,深度和模板测试也同样使用了多采样点。比如深度测试,顶点的深度值在运行深度测试前被插值到每个子样本中,对于模板测试,我们为每个子样本储存模板值,而不是每个像素。这意味着深度和模板缓冲的大小随着像素子样本的增加也增加了。
|
不仅颜色值会被多重采样技术影响,深度测试和模板测试也同样使用了多重采样技术。比如深度测试,顶点的深度值在运行深度测试前被插值到每个子采样中,对于模板测试,我们为每个子采样储存模板值,而不是每个像素。这意味着深度和模板缓冲的大小随着像素子样本的增加也增加了。
|
||||||
|
|
||||||
|
到目前为止我们所讨论的不过是多重采样技术的工作原理。光栅化背后实际的逻辑要比我们讨论的复杂,但你现在可以理解MSAA背后的概念和逻辑了。
|
||||||
|
(译者注: 如果看到这里还是对原理似懂非懂,可以简单看看知乎上[@文刀秋二](https://www.zhihu.com/people/edliu/answers) 对抗锯齿技术的[精彩介绍](https://www.zhihu.com/question/20236638/answer/14438218))
|
||||||
|
|
||||||
到目前为止我们所讨论的不过是多采样发走样工作的方式。光栅化背后实际的逻辑要比我们讨论的复杂,但你现在可以理解多采样抗锯齿背后的概念和逻辑了。
|
|
||||||
|
|
||||||
## OpenGL中的MSAA
|
## OpenGL中的MSAA
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user