1
0
mirror of https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git synced 2025-08-22 20:25:28 +08:00

Move all the images to this repo. Close #53

This commit is contained in:
Meow J
2016-09-17 02:11:48 +08:00
parent b384a9f176
commit f0dd66f4b9
246 changed files with 221 additions and 221 deletions

View File

@@ -10,17 +10,17 @@
**延迟着色法(Deferred Shading)****或者说是延迟渲染(Deferred Rendering)**为了解决上述问题而诞生了它大幅度地改变了我们渲染物体的方式。这给我们优化拥有大量光源的场景提供了很多的选择因为它能够在渲染上百甚至上千光源的同时还能够保持能让人接受的帧率。下面这张图片包含了一共1874个点光源它是使用延迟着色法来完成的而这对于正向渲染几乎是不可能的(图片来源Hannes Nevalainen)。
![](http://learnopengl.com/img/advanced-lighting/deferred_example.png)
![](../img/05/08/deferred_example.png)
延迟着色法基于我们**延迟(Defer)**或**推迟(Postpone)**大部分计算量非常大的渲染(像是光照)到后期进行处理的想法。它包含两个处理阶段(Pass):在第一个几何处理阶段(Geometry Pass)中我们先渲染场景一次之后获取对象的各种几何信息并储存在一系列叫做G缓冲(G-buffer)的纹理中;想想位置向量(Position Vector)、颜色向量(Color Vector)、法向量(Normal Vector)和/或镜面值(Specular Value)。场景中这些储存在G缓冲中的几何信息将会在之后用来做(更复杂的)光照计算。下面是一帧中G缓冲的内容
![](http://learnopengl.com/img/advanced-lighting/deferred_g_buffer.png)
![](../img/05/08/deferred_g_buffer.png)
我们会在第二个光照处理阶段(Lighting Pass)中使用G缓冲内的纹理数据。在光照处理阶段中我们渲染一个屏幕大小的方形并使用G缓冲中的几何数据对每一个片段计算场景的光照在每个像素中我们都会对G缓冲进行迭代。我们对于渲染过程进行解耦将它高级的片段处理挪到后期进行而不是直接将每个对象从顶点着色器带到片段着色器。光照计算过程还是和我们以前一样但是现在我们需要从对应的G缓冲而不是顶点着色器(和一些uniform变量)那里获取输入变量了。
下面这幅图片很好地展示了延迟着色法的整个过程:
![](http://learnopengl.com/img/advanced-lighting/deferred_overview.png)
![](../img/05/08/deferred_overview.png)
这种渲染方法一个很大的好处就是能保证在G缓冲中的片段和在屏幕上呈现的像素所包含的片段信息是一样的因为深度测试已经最终将这里的片段信息作为最顶层的片段。这样保证了对于在光照处理阶段中处理的每一个像素都只处理一次所以我们能够省下很多无用的渲染调用。除此之外延迟渲染还允许我们做更多的优化从而渲染更多的光源。
@@ -145,7 +145,7 @@ void main()
如果我们现在想要渲染一大堆纳米装战士对象到`gBuffer`帧缓冲中,并通过一个一个分别投影它的颜色缓冲到铺屏四边形中尝试将他们显示出来,我们会看到向下面这样的东西:
![](http://learnopengl.com/img/advanced-lighting/deferred_g_buffer.png)
![](../img/05/08/deferred_g_buffer.png)
尝试想象世界空间位置和法向量都是正确的。比如说指向右侧的法向量将会被更多地对齐到红色上从场景原点指向右侧的位置矢量也同样是这样。一旦你对G缓冲中的内容满意了我们就该进入到下一步光照处理阶段了。
@@ -220,7 +220,7 @@ void main()
运行一个包含32个小光源的简单Demo会是像这样子的
![](http://learnopengl.com/img/advanced-lighting/deferred_shading.png)
![](../img/05/08/deferred_shading.png)
你可以在以下位置找到Demo的完整[源代码](http://learnopengl.com/code_viewer.php?code=advanced-lighting/deferred),和几何渲染阶段的[顶点](http://learnopengl.com/code_viewer.php?code=advanced-lighting/deferred_geometry&type=vertex)和[片段](http://learnopengl.com/code_viewer.php?code=advanced-lighting/deferred_geometry&type=fragment)着色器,还有光照渲染阶段的[顶点](http://learnopengl.com/code_viewer.php?code=advanced-lighting/deferred&type=vertex)和[片段](http://learnopengl.com/code_viewer.php?code=advanced-lighting/deferred&type=vertex)着色器。
@@ -254,7 +254,7 @@ for (GLuint i = 0; i < lightPositions.size(); i++)
然而,这些渲染出来的立方体并没有考虑到我们储存的延迟渲染器的几何深度(Depth)信息,并且结果是它被渲染在之前渲染过的物体之上,这并不是我们想要的结果。
![](http://learnopengl.com/img/advanced-lighting/deferred_lights_no_depth.png)
![](../img/05/08/deferred_lights_no_depth.png)
我们需要做的就是首先复制出在几何渲染阶段中储存的深度信息,并输出到默认的帧缓冲的深度缓冲,然后我们才渲染光立方体。这样之后只有当它在之前渲染过的几何体上方的时候,光立方体的片段才会被渲染出来。我们可以使用`glBlitFramebuffer`复制一个帧缓冲的内容到另一个帧缓冲中,这个函数我们也在[抗锯齿](http://learnopengl-cn.readthedocs.org/zh/latest/04%20Advanced%20OpenGL/11%20Anti%20Aliasing/)的教程中使用过,用来还原多重采样的帧缓冲。`glBlitFramebuffer`这个函数允许我们复制一个用户定义的帧缓冲区域到另一个用户定义的帧缓冲区域。
@@ -273,7 +273,7 @@ glBindFramebuffer(GL_FRAMEBUFFER, 0);
在这里我们复制整个读帧缓冲的深度缓冲信息到默认帧缓冲的深度缓冲对于颜色缓冲和模板缓冲我们也可以这样处理。现在如果我们接下来再渲染光立方体场景里的几何体将会看起来很真实了而不只是简单地粘贴立方体到2D方形之上
![](http://learnopengl.com/img/advanced-lighting/deferred_lights_depth.png)
![](../img/05/08/deferred_lights_depth.png)
你可以在[这里](http://learnopengl.com/code_viewer.php?code=advanced-lighting/deferred_light_cube)找到Demo的源代码还有光立方体的[顶点](http://learnopengl.com/code_viewer.php?code=advanced-lighting/deferred_light_cube&type=vertex)和[片段](http://learnopengl.com/code_viewer.php?code=advanced-lighting/deferred_light_cube&type=fragment)着色器。
@@ -387,7 +387,7 @@ void main()
使用光体积更好的方法是渲染一个实际的球体,并根据光体积的半径缩放。这些球的中心放置在光源的位置,由于它是根据光体积半径缩放的,这个球体正好覆盖了光的可视体积。这就是我们的技巧:我们使用大体相同的延迟片段着色器来渲染球体。因为球体产生了完全匹配于受影响像素的着色器调用,我们只渲染了受影响的像素而跳过其它的像素。下面这幅图展示了这一技巧:
![](http://learnopengl.com/img/advanced-lighting/deferred_light_volume_rendered.png)
![](../img/05/08/deferred_light_volume_rendered.png)
它被应用在场景中每个光源上,并且所得的片段相加混合在一起。这个结果和之前场景是一样的,但这一次只渲染对于光源相关的片段。它有效地减少了从`nr_objects * nr_lights`到`nr_objects + nr_lights`的计算量,这使得多光源场景的渲染变得无比高效。这正是为什么延迟渲染非常适合渲染很大数量光源。