参考教程
《Real-Time Rendering 3rd》
《GPU-Programming-AndCgLanguage-Primer》
学习记录
在计算机图形中,延迟渲染(Deferred Rendering),即延迟着色(Deferred Shading)是将着色计算延迟到深度测试之后进行处理的一种渲染方法。延迟着色技术最大的优势就是将光源的数目和场景中物体的数目在复杂度层面上完全分开,能够在渲染拥有成百上千光源的场景的同时依然保持很高的帧率,给我们渲染拥有大量光源的场景提供了很多可能性。
这篇文章,我们简单介绍延迟渲染的实现。
延迟渲染的实现我们主要分为两步,第一步将所有物体绘制到屏幕缓冲(G-Buffer),第二部在深度测试后进行光照计算,对应于正向渲染(Forward Rendering)O(m*n)的复杂度场景,延迟渲染的复杂度仅仅为 O(m+n),因为它避免了对在深度测试中被丢弃的片元的渲染。
Deferred shading is the process of splitting up traditional rendering into a two stage system that is designed to improve efficiency in shaders that require complex lighting.
In the first stage we render as usual by using a vertex and pixel shader.However the purpose of the pixel shader is entirely different.We no longer use the pixel shader to do lighting calculations and then output a color to the back buffer.We instead output information about that pixel (such as normals, texture color, and so forth) to a render to texture buffer.So now our pixel shader output from the first stage has become a 2D texture full of scene information that can be used as a texture input to the second stage.
In the second stage we re-write all our traditional 3D shaders to now do 2D post processing using the render to texture outputs from the first stage.And because we are doing 2D post processing we have just a set number of pixels to run our lighting equations on instead of a massive scene full of thousands of complex 3D objects.Therefore it no longer matters if we have thousands of lights in our scene or how many polygons are in each object.We only perform lighting equations on the very final 2D output pixels.
So deferred shading eliminates all sorts of calculations that would be required in the vertex and pixel shader for every single model in the scene.And all those complex calculations create output data that is usually discarded anyhow due to culling.So all those inefficiencies are now eliminated and our shading equations are now a fixed amount of processing regardless of scene size, number of lights, and so forth.This really opens the door so we can do more complex lighting as well as simplify and combine our shaders that already required 2D post processing.
首先我们有一个 DeferredBufferClass
类来定义我们的 G-Buffer
,在这里我们 Buffer
中存储颜色和法线的信息,这个类由 RenderToTexture
修改而来,他如今有多个缓冲以用于将不同的属性(颜色,法线)来存储在不同位置,其声明如下:
1 | ///////////// |
之后我们将使用 DeferredShaderClass
类来将场景渲染至我们的 G-Buffer
,首先来看我们的着色器,如下:
1 | //////////////////////////////////////////////////////////////////////////////// |
顶点着色器和以往一样,像素着色器中,我们将渲染物体的颜色(color)和法线(normal)分别输出给不同的 TARGET
。
他们的 ShaderClass
相比较 TextureShaderClass
几乎没有做修改,如下:
1 | //////////////////////////////////////////////////////////////////////////////// |
这样,在像素着色器阶段,我们并未做太多的运算,当渲染正常进行深度测试后,我们使用 G-Buffer
中的颜色纹理和法线纹理计算光照。这样我们计算的光照只有最终渲染的屏幕大小(width * height),当场景中存在大量物体的时候,延迟渲染显然比正向渲染快速的多。当然,由于需要存储 G-Buffer
,占用空间自然也多了一些。
最终渲染结果和普通渲染一个,我们所渲染的 cube 如下: