您的位置:首页 > Web前端

Forwar Rendering vs. Deferred Rendering

2016-07-06 21:47 183 查看
译者:i_dovelemon

日期:2016 / 07 / 05

来源:http://gamedevelopment.tutsplus.com/articles/forward-rendering-vs-deferred-rendering--gamedev-12342

主题:fowward rendering, deferred rendering

        如果你是一个3D游戏开发者,那么当你在探索游戏引擎的时候,你可能会遇到这两个名词:forward rendering和deferred rendering。同时,你也必须在你的游戏中选择一种来实现。但是,它们是什么意思了?它们之间又有什么不同了?在做选择的时候,我们又该选择哪一个了?



图1 Defered Rendering for many lights

现代图形渲染管线

         在开始之前,我们先来了解下当前现代的渲染管线是什么样的。

        在以前,由于显卡的限制,我们在渲染的时候能够做的东西少的可怜。我们不能够改变一个像素的绘制过程,只有通过传递不同的纹理来改变像素,一旦顶点数据到达显卡之后,我们就再也没有机会对它进行额外的修改。但是时代发生了改变,我们现在的渲染管线都是能够被我们通过编程来进行控制的。我们能够发送一些代码到显卡上,以此来控制一个像素最终的样子,通过为一个表面添加额外的法线贴图来实现表面的凹凸感,同时也能够增加物质表面的反射效果。

        这个代码就是我们常常看到的geometry shader,vertex shader和fragment shader,通过他们我们能够很容易的控制显卡如何渲染我们的像素。



图2

Forward Rendering

        Forward rendering是一种标准的,最常使用到的渲染方式,大部分的游戏引擎都支持这项功能。你将你的几何数据提交到显卡上去,它经过计算,将结果投影到投影平面,然后拆分成一个个单独的顶点,这些顶点再经过转换,裁剪,最终变成一个一个的像素,这个像素最终将被显示在我们的屏幕上去。



图3

        从上面的图中可以看到,这个渲染的方式是一种线性的过程,一个阶段进行一样工作,一个阶段接着一个阶段,直到最后形成一个完整的图像。

Deferred Rendering

        在Deferred rendering中,正如这个名字(延迟渲染)所指出的那样,渲染的操作被延迟了一会儿,当所有的数据都被处理完成,并且传递到图形管线的最后的时候,我们在最后进行实际的光照计算,然后形成一张新的图像。

        那么,我们为什么要这么做了?



图4

        而Deferred lighting技术能够通过更多的渲染pass来减小G-buffer的尺寸。

Light Performance

        光照是Forward rendering和Deferred Rendering的主要区别。在一个标准的Forward rendering渲染管线中,光照计算需要在每一个顶点或者每一个片段上进行,而且每一个灯光都要进行这么多的计算。

        如果你的场景有100个几何体,每一个几何体有1000个顶点,那么你大概就有100000个多边形需要进行处理。当然了,现代的图形卡处理这些数据还是很快的。但是当我们在片段着色器中进行光照计算的时候,并且需要计算的光源又比较多的时候,就会导致渲染速度飞快的下降。

        所以,开发者们尽量在顶点着色器中进行光照计算,从而减少在片段着色器中进行光照计算。在片段着色器中进行的计算,不管这个像素是否在后面会被其他的像素所遮盖,也不会是否在视口中可见,它们都需要通过片段着色器进行一次渲染操作。比如,你有一个屏幕,它的分辨率大概在1024×768,
那么你大概要渲染的也就只有800000个像素而已。在这样的情况下,我们的图形卡很容易就需要每帧处理百万级的片段。但是,大部分的像素实际上最终都没有显示在屏幕上,那么对这些像素进行光照计算完全是浪费的。

        如果你有百万级的片段要进行渲染,那么对于每一个灯光都需要渲染这么多的片段,总的就需要渲染很多的片段了。

        对于Forward rendering的渲染算法复杂度,大概为O(num_geometry_fragment * num_lights)。你可以看到这个算法复杂度完全依赖与场景的几何片段以及灯光的数量。

        如果在深度测试的过程中,一个片段没有被丢弃掉,那么这个像素最终就需要显示在屏幕上。

        现在,很多的引擎在光源的处理上进行优化,比如将多个光源组合起来,或者使用光照贴图来模拟光照。但是,如果你的场景需要很多的灯光,那么我们就需要一些更好的处理方法。

Deferred Rendering to the Rescue

        延迟渲染是一个非常有趣的方案,能够通过这个方法来减少渲染对象的数量,减少渲染片段的数量,我们仅仅需要对最终需要在屏幕上显示的像素进行光照计算,也就是说我们将需要渲染的片段数量降低到整个屏幕的像素数量。

        同样的,延迟渲染的算法复杂度为O(screen_resolution * num_lights)。

        从上面那个算法复杂度,你能够看到这个算法的复杂度和需要渲染的对象数量没有关系,仅仅和我们的屏幕像素有关系,所以,我们就能够大大的提高我们需要使用的光源数量。(读者请注意,这并不表示,你能够绘制无数的物体,提交batch的消耗依然存在,不过GPU放松了很多)。

The Guts of Deferred Rendering

       每一个几何体都需要被渲染,但是不需要进行光照计算,我们需要多个渲染目标来实现这个算法。一般来说,深度渲染目标,法线渲染目标和颜色渲染目标。有了这些信息,我们就能够对每一个灯光,每一个像素进行光照计算。



图5



图6

        如果,我们知道了一个像素有多远,它的法线,我们就能够通过这些知识来为每一个像素计算光照。

Which to Pick?

        如果你的场景中有很多动态的光源,那么你就需要使用延迟渲染。但是,同样的我们需要知道延迟渲染的一些缺点:

这个渲染算法需要我们的显卡能够支持多渲染目标。老式的显卡可能不支持这个功能
需要更高的显卡带宽。从前面我们知道,需要对多个渲染目标传递信息,也就是说老的显卡可能承受不了这么大的带宽。
你不能够使用透明的物体。(除非你组合Forward rendering和Deferred rendering算法)
没办法实现抗锯齿。好吧,只有一些引擎可能不支持采样,你依然能够通过边缘检测,FXAA等算法来实现。
只支持一种材质,除非你使用的是Deferred Rendering算法的一种变体,Deferred Lighting.
阴影的产生依然依赖于光源的数量。
        如果你没有那么多的光源需要处理,并且你希望你的游戏能够在较老的硬件上运行起来,那么你就使用Forward rendering吧。通过Light map来代替场景中的动态光源,依然能够实现很多看起来非常酷的效果。

Conclusion

        我希望我上面的介绍能够给你带来一点启示。你需要仔细的斟酌,选择最适合你项目的方式来进行渲染。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: