1
0
mirror of https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git synced 2025-08-23 04:35:28 +08:00

更新“抗锯齿”译文+灰度化图片

This commit is contained in:
1i9h7_b1u3
2025-01-26 14:34:56 +08:00
parent bd752a5030
commit 3bef01a3a9
2 changed files with 11 additions and 11 deletions

View File

@@ -36,7 +36,7 @@
由于屏幕像素总量的限制,有些边缘的像素能够被渲染出来,而有些则不会。结果就是我们使用了不光滑的边缘来渲染图元,导致之前讨论到的锯齿边缘。
多重采样所做的正是将单一的采样点变为多个采样点这也是它名称的由来。我们不再使用像素中心的单一采样点取而代之的是以特定图案排列的4个子采样点(Subsample)。我们将用这些子采样点来决定像素的遮盖度。当然,这也意味着颜色缓冲的大小会随着子采样点的增加而增加。
多重采样所做的正是将单一的采样点变为多个采样点这也是它名称的由来。我们不再使用像素中心的单一采样点取而代之的是以特定图案排列的4个子采样点(Subsample)。我们将用这些子采样点来决定像素的遮盖度。
![](../img/04/11/anti_aliasing_sample_points.png)
@@ -48,7 +48,7 @@
从这里开始多重采样就变得有趣起来了。我们知道三角形只遮盖了2个子采样点所以下一步是决定这个像素的颜色。你的猜想可能是我们对每个被遮盖住的子采样点运行一次片段着色器最后将每个像素所有子采样点的颜色平均一下。在这个例子中我们需要在两个子采样点上对被插值的顶点数据运行两次片段着色器并将结果的颜色储存在这些采样点中。幸运的是这并**不是**它工作的方式,因为这本质上说还是需要运行更多次的片段着色器,会显著地降低性能。
MSAA真正的工作方式是无论三角形遮盖了多少个子采样点每个图元中每个像素只运行**一次**片段着色器。片段着色器使用的顶点数据会插值到每个像素**中心**,所得到的结果颜色会被储存在每个被遮盖住的子采样点中。当颜色缓冲的子样本被图元的所有颜色填满时,所有的这些颜色将会在每个像素内部平均化。因为上图的4个采样点中只有2个被遮盖住了这个像素的颜色将会是三角形颜色与其他两个采样点的颜色(在这里是无色)的平均值,最终形成一种淡蓝色。
MSAA真正的工作方式是无论三角形遮盖了多少个子采样点每个图元中每个像素只运行**一次**片段着色器。片段着色器使用插值到像素**中心**的顶点数据然后MSAA使用更大的深度/模板缓冲区来确定子采样点的覆盖率。被覆盖的子采样点数量将决定了像素颜色对帧缓冲的影响程度。因为上图的4个采样点中只有2个被遮盖住了所以三角形颜色会有一半与帧缓冲区的颜色(在这里是无色)进行混合,最终形成一种淡蓝色。
这样子做之后,颜色缓冲中所有的图元边缘将会产生一种更平滑的图形。让我们来看看前面三角形的多重采样会是什么样子:
@@ -60,9 +60,9 @@ MSAA真正的工作方式是无论三角形遮盖了多少个子采样点
![](../img/04/11/anti_aliasing_rasterization_samples_filled.png)
对于每个像素来说,越少的子采样点被三角形所覆盖,那么它受到三角形的影响就越小。三角形的不平滑边缘被稍浅的颜色所包围后,从远处观察时就会显得更加平滑了。
三角形的不平滑边缘被稍浅的颜色所包围后,从远处观察时就会显得更加平滑了。
不仅仅是颜色值会受到多重采样的影响,深度和模板测试也能够使用多个采样点。对深度测试来说,每个顶点的深度值会在运行深度测试之前被插值到各个子样本中。对模板测试来说,我们每个子样本,而不是每个像素,存储一个模板值。当然,这意味着深度和模板缓冲的大小会乘以子采样点的个数
深度和模板值会按各个子采样点存储,并且当多个三角形重叠单个像素时,即使我们只运行一次片段着色器,颜色值也依然会按子采样点存储。对深度测试来说,在运行深度测试之前,每个顶点的深度值会被插值到各个子样本中。对模板测试来说,我们会为每个子样本存储模板值,这意味着缓冲的大小会根据每个像素的子采样点数量而相应增加
我们到目前为止讨论的都是多重采样抗锯齿的背后原理,光栅器背后的实际逻辑比目前讨论的要复杂,但你现在应该已经可以理解多重采样抗锯齿的大体概念和逻辑了。
@@ -87,15 +87,15 @@ glfwWindowHint(GLFW_SAMPLES, 4);
glEnable(GL_MULTISAMPLE);
```
只要默认的帧缓冲有了多重采样缓冲的附件,我们所要做的只是调用<fun>glEnable</fun>来启用多重采样。因为多重采样的算法都在OpenGL驱动的光栅器中实现了我们不需要再多做什么。如果现在再来渲染本节一开始的那个绿色的立方体我们应该能看到更平滑的边缘
因为多重采样的算法都在OpenGL驱动的光栅器中实现了我们不需要再多做什么。如果现在再来渲染本节一开始的那个绿色的立方体我们应该能看到更平滑的边缘
![](../img/04/11/anti_aliasing_multisampled.png)
这个箱子看起来的确要平滑多了,如果在场景中有其它的物体,它们也会看起来平滑很多。你可以在[这里](https://learnopengl.com/code_viewer.php?code=advanced/anti_aliasing_multisampling)找到这个简单例子的源代码。
这个箱子看起来的确要平滑多了,如果在场景中有其它的物体,它们也会看起来平滑很多。你可以在[这里](https://learnopengl.com/code_viewer_gh.php?code=src/4.advanced_opengl/11.1.anti_aliasing_msaa/anti_aliasing_msaa.cpp)找到这个简单例子的源代码。
## 离屏MSAA
由于GLFW负责了创建多重采样缓冲启用MSAA非常简单。然而如果我们想要使用我们自己的帧缓冲来进行离屏渲染那么我们就必须要自己动手生成多重采样缓冲了。
由于GLFW负责了创建多重采样缓冲启用MSAA非常简单。然而如果我们想要使用我们自己的帧缓冲来进行离屏渲染那么我们就必须要自己动手生成多重采样缓冲了。现在,我们**确实**需要自己创建多重采样缓冲区。
有两种方式可以创建多重采样缓冲,将其作为帧缓冲的附件:纹理附件和渲染缓冲附件,这和在[帧缓冲](05 Framebuffers.md)教程中所讨论的普通附件很相似。
@@ -131,7 +131,7 @@ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width,
### 渲染到多重采样帧缓冲
渲染到多重采样帧缓冲对象的过程都是自动的。只要我们在帧缓冲绑定时绘制任何东西,光栅器就会负责所有的多重采样运算。我们最终会得到一个多重采样颜色缓冲以及/或深度和模板缓冲。因为多重采样缓冲有一点特别,我们不能直接将它们的缓冲图像用于其他运算,比如在着色器中对它们进行采样。
渲染到多重采样帧缓冲对象的过程非常简单。只要我们在帧缓冲绑定时绘制任何东西,光栅器就会负责所有的多重采样运算。我们最终会得到一个多重采样颜色缓冲以及/或深度和模板缓冲。因为多重采样缓冲有一点特别,我们不能直接将它们的缓冲图像用于其他运算,比如在着色器中对它们进行采样。
一个多重采样的图像包含比普通图像更多的信息,我们所要做的是缩小或者<def>还原</def>(Resolve)图像。多重采样帧缓冲的还原通常是通过<fun>glBlitFramebuffer</fun>来完成,它能够将一个帧缓冲中的某个区域复制到另一个帧缓冲中,并且将多重采样缓冲还原。
@@ -147,7 +147,7 @@ glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
![](../img/04/11/anti_aliasing_multisampled.png)
你可以在[这里](https://learnopengl.com/code_viewer_gh.php?code=src/4.advanced_opengl/11.anti_aliasing_offscreen/anti_aliasing_offscreen.cpp)找到源代码。
你可以在[这里](https://learnopengl.com/code_viewer_gh.php?code=src/4.advanced_opengl/11.2.anti_aliasing_offscreen/anti_aliasing_offscreen.cpp)找到源代码。
但如果我们想要使用多重采样帧缓冲的纹理输出来做像是后期处理这样的事情呢我们不能直接在片段着色器中使用多重采样的纹理。但我们能做的是将多重采样缓冲位块传送到一个没有使用多重采样纹理附件的FBO中。然后用这个普通的颜色附件来做后期处理从而达到我们的目的。然而这也意味着我们需要生成一个新的FBO作为中介帧缓冲对象将多重采样缓冲还原为一个能在着色器中使用的普通2D纹理。这个过程的伪代码是这样的
@@ -178,9 +178,9 @@ while(!glfwWindowShouldClose(window))
}
```
如果现在再实现[帧缓冲](05 Framebuffers.md)教程中的后期处理效果,我们就能够在一个几乎没有锯齿的场景纹理上进行后期处理了。如果施加模糊的核滤镜,看起来将会是这样:
如果现在再实现[帧缓冲](05 Framebuffers.md)教程中的后期处理效果,我们就能够在一个几乎没有锯齿的场景纹理上进行后期处理了。如果让图像灰度化,看起来将会是这样:
![](../img/04/11/anti_aliasing_post_processing.png)
![](../img/04/11/anti_aliasing_post_processing_grayscale.png)
!!! Important

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB