霸州 网络 网站建设,网站编辑培训学校,做珠宝网站价格多少,网站搭建Rendering Path其实指的就是渲染场景中光照的方式。由于场景中的光源可能很多#xff0c;甚至是动态的光源。所以怎么在速度和效果上达到一个最好的结果确实很困难。以当今的显卡发展为契机#xff0c;人们才衍生出了这么多的Rendering Path来处理各种光照。
一. 正向渲染Fo…Rendering Path其实指的就是渲染场景中光照的方式。由于场景中的光源可能很多甚至是动态的光源。所以怎么在速度和效果上达到一个最好的结果确实很困难。以当今的显卡发展为契机人们才衍生出了这么多的Rendering Path来处理各种光照。
一. 正向渲染Forward Rendering
正向渲染(Forward Rendering)或称正向着色(Forward Shading)是渲染物体的一种非常直接的方式在场景中我们根据所有光源照亮一个物体之后再渲染下一个物体以此类推。要使用Forward Rendering一般在Vertex Shader或Fragment Shader阶段对每个顶点或每个像素进行光照计算并且是对每个光源进行计算产生最终结果。 正向渲染的渲染管线流程下面是Forward Rendering的核心伪代码。
For each light:For each object affected by the light:framebuffer object * light
传统的正向渲染思路是先进行着色再进行深度测试。其的主要缺点就是光照计算跟场景复杂度和光源个数有很大关系。假设有n个物体m个光源且每个每个物体受所有光源的影响那么复杂度就是O(m*n)所以比较适合户外这种光源较少的场景一般只有太阳光。因为如果在 vertex shader 中计算光照其复杂度将是O(num_geometry_vertexes ∗ num_lights)而如果在 fragment shader 中计算光照其复杂度为O(num_geometry_fragments ∗ num_lights) 。可见 光源数目和复杂度是成线性增长的。
正向渲染简单直接也很容易实现但是同时它对程序性能的影响也很大因为对每一个需要渲染的物体程序都要对每个光源下每一个需要渲染的片段进行迭代如果旧的片段完全被一些新的片段覆盖最终无需显示出来那么其着色计算花费的时间就完全浪费掉了。
Unity中的正向渲染
在Unity中前向渲染规则如下一个场景中多光照情形按光源的重要程度排序ABCD四盏灯用效果最好的逐像素方式渲染光照DEFG用逐顶点方式渲染光照GH则用球谐光照方式计算光照。关于球谐光的一些知识可以参考我的这篇文章https://blog.csdn.net/yinfourever/article/details/90205890 Unity中正向渲染分为一个Base Pass和多个Additional Passes.
Base Pass: 用逐像素的方式渲染一个directional light 所有球谐光和逐顶点光。在这个pass里也会计算lightmap等directional light可以计算阴影要注意如果使用了lightmap照亮的物体不会被球谐光照亮。
Additional Passes每个其他需要用逐像素渲染的光源将会用一个Addtional pass渲染默认情况下这些灯光不会有阴影除非使用了 multi_compile_fwdadd_fullshadows variant shortcut
更详细的信息可以参考Unity官方文档中关于Forward Rendering的介绍https://docs.unity3d.com/2019.2/Documentation/Manual/RenderTech-ForwardRendering.html 二. 延迟渲染 Deferred Rendering
延迟渲染( Deferred Rendering)即延迟着色Deferred Shading顾名思义是将着色计算延后进行处理的一种渲染方法在2004年的GDC上被正式提出 http://www.tenacioussoftware.com/gdc_2004_deferred_shading.ppt。
延迟着色给我们优化拥有大量光源的场景提供了很多可能性因为它能够在渲染拥有成百上千光源的场景的同时还能够保持能让人接受的帧率。下面这张图展示了一个基于延迟着色渲染出的场景这个场景中包含了1000个点光源对于目前的硬件设备而言用传统的正向渲染来实现几乎是不可能的。
基于Deferred Rendering 渲染的含1000个点光源的场景 [J. Andersson, SIGGRAPH 2009 Beyond Programmable shading course talk] Frostbite 2引擎可以将延迟渲染( Deferred Rendering)理解为先将所有物体都先绘制到屏幕空间的缓冲即G-bufferGeometric Buffer几何缓冲区中再逐光源对该缓冲进行着色的过程从而避免了因计算被深度测试丢弃的⽚元的着色而产⽣的不必要的开销。也就是说延迟渲染基本思想是先执行深度测试再进行着色计算将本来在物空 间三维空间进行光照计算放到了像空间二维空间进行处理。
可以将延迟渲染理解为两个Pass的过程
1、几何处理阶段(Geometry Pass)。这个阶段中我们获取对象的各种几何信息并将第二步所需的各种数据储存也就是渲染到多个G-buffer中
2、光照处理阶段(Lighting Pass)。在这个pass中我们只需渲染出一个屏幕大小的二维矩形使用第一步在G-buffer中存储的数据对此矩阵的每一个片段计算场景的光照光照计算的过程还是和正向渲染以前一样只是现在我们需要从对应的G-buffer而不是顶点着色器(和一些uniform变量)那里获取输入变量了。 延迟着色的过程延迟着色中一个非常重要的概念就是G-Buffer下面先聊一下G-Buffer。
G-Buffer全称Geometric Buffer 译作几何缓冲区它主要用于存储每个像素对应的位置Position法线Normal漫反射颜色Diffuse Color以及其他有用材质参数。根据这些信息就可以在像空间二维空间中对每个像素进行光照处理。G-Buffer根据需求可以存储不同的内容以下为一个典型的G-Buffer layout对于Unity中的Deferred RenderingG-Buffer layout就与之下的不同关于Unity的部分之后会再细说。 一个典型的G-buffer layout。Source: W. Engel, “Light-Prepass Renderer Mark III” SIGGRAPH 2009Talks下面是一帧中G-buffer中存储的内容 G-buffer存储的信息延迟渲染方法一个很大的好处就是能保证在G-buffer中的片段和在屏幕上呈现的像素所包含的片段信息是一样的因为深度测试已经最终将这里的片段信息作为最顶层的片段。这样保证了对于在光照处理阶段中处理的每一个像素都只处理一次所以我们能够省下很多无用的渲染调用。除此之外延迟渲染还允许我们做更多的优化从而渲染更多的光源。
在几何处理阶段中填充G-buffer非常高效因为我们直接储存位置颜色法线等对象信息到帧缓冲中这个过程几乎不消耗处理时间。而在此基础上使用多渲染目标(Multiple Render Targets, MRT)技术我们可以在一个Pass之内完成所有渲染工作。
总结一下典型的Deferred Rendering 的渲染流程有两步
1. 几何处理阶段渲染所有的几何/颜色数据到G-buffer2. 光照处理阶段使用G-buffer计算场景的光照。
通用版本的延迟着色算法伪代码
For each object:Render to multiple targets
For each light:Apply light as a 2D postprocess 延迟渲染( Deferred Rendering)管线流程初步总结对比下延迟渲染和正向渲染 正向渲染
正向渲染Forward Rendering先执行着色计算再执行深度测试。正向渲染渲染n个物体在m个光源下的着色复杂度为O(n*m)次。Forward Rendering光源数量对计算复杂度影响巨大所以比较适合户外这种光源较少的场景。延迟渲染
延迟渲染( Deferred Rendering)先执行深度测试再执行着色计算。延迟渲染渲染n个物体在m个光源下的着色复杂度为O(nm)次几何处理阶段n次渲染到G-buffer,着色阶段m个光源渲染m次。Deferred Rendering 的最大的优势就是将光源的数目和场景中物体的数目在复杂度层面上完全分开。也就是说场景中不管是一个三角形还是一百万个三角形最后的复杂度不会随 光源数目变化而产生巨大变化。
总结下延迟渲染优缺点
延迟渲染的优点 Deferred Rendering 的最大的优势就是将光源的数目和场景中物体的数目在复杂度层面上完全分开。也就是说场景中不管是一个三角形还是一百万个三角形最后的复杂度不会随光源数目变化而产生巨大变化。
复杂度仅O(nm)。只渲染可见的像素节省计算量。用更少的shader。对后处理支持良好。在大量光源的场景优势尤其明显。
延迟渲染的缺点
内存开销较大。读写G-buffer的内存带宽用量是性能瓶颈。对透明物体的渲染存在问题。在这点上需要结合正向渲染进行渲染。对多重采样抗锯齿MultiSampling Anti-Aliasing, MSAA的支持不友好主要因为需开启MRT。由于Deferred Shading的Deferred阶段是在完全基于G-Buffer的屏幕空间进行这也导致了物体材质信息的缺失这样在处理多变的渲染风格时就需要额外的操作。
Unity中的延迟渲染
在Unity5之后使用了延迟渲染deferred rendering代替了之前版本的延迟光照Deferred Lighting light prepass关于延迟光照在下一小节会简要介绍。
在Unity中G-buffer layout G-Buffer pass
The g-buffer pass renders each GameObject once. Diffuse and specular colors, surface smoothness, world space normal, and emissionambientreflectionslightmaps are rendered into g-buffer textures. The g-buffer textures are setup as global shader properties for later access by shaders (CameraGBufferTexture0 ..CameraGBufferTexture3 names).
Lighting pass
The lighting pass computes lighting based on g-buffer and depth. Lighting is computed in screen space, so the time it takes to process is independent of Scene complexity. Lighting is added to the emission buffer.
延迟渲染只支持standard lighting model如果想替换自己的shader效果可以修改lighting pass shader。
更详细的信息可以参考Unity官方文档 https://docs.unity3d.com/Manual/RenderTech-DeferredShading.html
三. 延迟光照 LightPre-Pass / Deferred Lighting
Light Pre-Pass即Deferred Lighting延迟光照旨在减少传统Defferred Rendering使用G-buffer 时占用的过多开销reduce G-buffer overhead最早由 Wolfgang Engel于2008年在他的博客(http://diaryofagraphicsprogrammer.blogspot.com/2008/03/light-pre-pass-renderer.html)中提到的。
延迟光照的具体的思路是
1、渲染场景中不透明opaque 的几何体。将法线向量n和镜面扩展因子specular spread factorm 写入缓冲区。这个n/m-buffer 缓冲区是一个类似 G-Buffer的缓冲区但包含的信息更少更轻量适合于单个输出颜色缓冲区因此不需要MRT支持。2、渲染光照。计算漫反射和镜面着色方程并将结果写入不同的漫反射和镜面反射累积缓冲区。这个过程可以在一个单独的pass中完成使用MRT或者用两个单独的pass。环境光照明可以在这个阶段使用一个 full-screen pass进行计算。3、对场景中的不透明几何体进行第二次渲染。从纹理中读取漫反射和镜面反射值对前面步骤中漫反射和镜面反射累积缓冲区的值进行调制并将最终结果写入最终的颜色缓冲区。若在上一阶段没有处理环境光照明则在此阶段应用环境光照明。4、使用非延迟着色方法渲染半透明几何体。
关于延迟着色和延迟光照经常会被弄混这边简单区分一下。
延迟着色Deferred Rendering又称延迟着色Deferred Shading在2004年的GDC上被提出。延迟光照Deferred Lighting又称Light Pre-Pass是延迟着色的一种改进在2008年被提出。
Deferred Rendering与Deferred Lighting在思想上的主要异同
Deferred Shading需要更大的G-Buffer来完成对Deferred阶段的前期准备而且一般需要硬件有MRT的支持可以说是硬件要求更高。Deferred Lighting需要两个几何体元的绘制过程来来完成整个渲染操作G-Pass与Shading pass。这个既是劣势也是优势由于Deferred Shading中的Deferred阶段是在完全基于G-Buffer的屏幕空间进行这也导致了物体材质信息的缺失这样在处理多变的渲染风格时就需要额外的操作而Deferred Lighting却可以在Shading阶段得到物体的材质信息进而使这一问题的处理变得较简单。
两种方法的上述操作均是只能完成对不透明物体的渲染而透明或半透明的物体则需额外的传统Pass来完成。
两者流程图的对比 Deferred Lighting流程图Deferred Shading流程图Unity中的Deferred Lighting
在Unity5版本之前其实使用的就是Deferred Lighting技术现在版本的Unity依然保留了该渲染模式称为Legacy Deferrred。 Lighting Rendering Path. 分为Base pass,Lighting Pass,Final Pass在这里就不细分析了主要技术原理和之前讲的基本一致 详细信息可以查看Unity的官方文档
https://docs.unity3d.com/Manual/RenderTech-DeferredLighting.html
明明浅墨大神的文章说Deferred Lighting是Deferred Shading的优化那为什么Unity要从Deferred Lighting转换成Deferred Shading
我个人的理解是
随着硬件的发展带宽越来越不是瓶颈Deferred Shading比Deferred Lighting少一个pass假设场景有M个物体N个参与计算的灯光Deferred Lighting是 DS渲染最终执行的次数是2MN, 而Deferred Shading执行的次数是MN,所以效率更高其实就是用空间换时间的概念
个人理解有可能不太正确不负任何责任还望大佬们指教。 四. 分块延迟渲染 Tile-BasedDeferred Rendering
作为传统Defferred Rendering的另一种主要改进分块延迟渲染Tile-Based Deferred RenderingTBDR旨在合理分摊开销amortize overhead自SIGGRAPH 2010上提出以来逐渐为业界所了解。实验数据表明TBDR在大量光源存在的情况下明显优于上文提到的Light Pre-Pass。
我们知道延迟渲染的瓶颈在于读写 G-buffer在大量光源下具体瓶颈将位于每个光源对 G-buffer的读取及与颜色缓冲区color buffer混合。这里的问题是每个光源即使它们的影响范围在屏幕空间上有重疉因为每个光源是在不同的绘制中进行所以会重复读取G-buffer中相同位置的数据计算后以相加混合方式写入颜色缓冲。光源越多内存带宽用量越大。
而分块延迟渲染的主要思想则是把屏幕分拆成细小的栅格例如每 32 × 32 象素作为一个分块tile。然后计算每个分块会受到哪些光源影响把那些光源的索引储存在分块的光源列表里。最后逐个分块进行着色对每像素读取 G-buffer 和光源列表及相关的光源信息。因此G-buffer的数据只会被读取1次且仅1次写入 color buffer也是1次且仅1次大幅降低内存带宽用量。不过这种方法需要计算光源会影响哪些分块这个计算又称为光源剔除light culling可以在 CPU 或 GPU通常以 compute shader 实现中进行。用GPU计算的好处是GPU 计算这类工作比 CPU 更快也减少 CPUGPU 数据传输。而且可以计算每个分块的深度范围depth range作更有效的剔除。 Tile-Based Deferred Rendering 图示 GDC2011SPU-based deferred shading for Battlefield 3 onPlaystation 3.也就是说TBDR 主要思想就是将屏幕分成一个个小块 tile。然后根据这些 Depth 求得每个 tile 的 bounding box。对每个 tile 的 bounding box 和 light 进行求交这样就得到了对该 tile 有作用 的 light 的序列。最后根据得到的序列计算所在 tile 的光照效果。
对比 Deferred Rendering之前是对每个光源求取其作用区域 light volume然后决定其作用的的 pixel也就是说每个光源要求取一次。而使用 TBDR只要遍历每个 pixel让其所属 tile 与光线求交来计算作用其上的 light并利用 G-Buffer 进行 Shading。一方面这样做减少 了所需考虑的光源个数另一方面与传统的 Deferred Rendering 相比减少了存取的带宽。
五. 分块正向渲染 Tiled Forward Rendering
Forward Forward Light Culling[6]。Forward很类似Tiled-based Deferred Rendering。其具体做法就是先对输入的场景进行z-prepass也就是说关闭写入color只向z-buffer写入z值。注意此步骤是Forward必须的而其他渲染方式是可选的。接下来来的步骤和TBDR很类似都是划分tiles并计算bounding box。只不过TBDR是在G-Buffer中完成这一步骤的而Forward是根据Z-Buffer。最后一步其实使用的是forward方式即在FS阶段对每个pixel根据其所在tile的light序列计算光照效果。而TBDR使用的是基于G-Buffer的deferred rendering。
实际上forward比deferred运行的更快。我们可以看出由于Forward只要写深度缓存就可以而Deferred Render除了深度缓存还要写入法向缓存。而在Light Culling步骤Forward只需要计算出哪些light对该tile有影响即可。而Deferred Render还在这一部分把光照处理给做了。而这一部分Forward是放在Shading阶段做的。所以Shading阶段Forward耗费更多时间。但是对目前硬件来说Shading耗费的时间没有那么多。 注意下这张图是forward与deferred lighting对比不是shading六. 总结下目前Unity传统渲染管线中支持RenderPath的情况 七. Unite2019中的部分相关内容
周末去上海参加了Unite大会讲道理确实干货满满。其中有一场技术演讲就是关于Unity最新Render path的Unity最新的SRP渲染管线中加入了Fine Pruned Tiled Light Lists和Clustered Shading技术提供Tiled Forward Rendering和Tile-BasedDeferred RenderingFine Pruned Tiled Light Lists和Clustered Shading技术原理可以参照Gpu Pro7中的文章我暂时也还没有去读之后会抽时间去学习下。
《Gpu Pro7》Clustered Shading: Assigning Lights Using Conservative Rasterization in DirectX 12使用Compute Shader以及DX12保守光栅化实现优化的分簇渲染三维空间划分光存储到Light-Linklist中降低光与物体映射的消耗。《Gpu Pro7》Fine Pruned Tiled Light Lists一种优化的Tiled Shading与传统的不同通过两个pass首先计算light在全屏的AABB进行粗略判断然后逐Tiled精确判断可以实现不规则光源的Tiled Shading而且利用Compute Shader生成再利用AMD的GCN架构上将这个计算和ShadowMap并行降低计算时间。用于《古墓丽影·崛起》。
Unity中通过Fine Pruned Tiled Light Lists技术为deferred和forward两种管线提供更优化的剔除功能相关的一些知识可以参考我下边拍摄的照片等Unity更新版本提供这些功能后以及我个人学习更多相关知识后我会再更新这篇文章。 八. 总结
总结下本文目前已经提到的Rendering Path有
正向渲染 Forward Rendering Unity中一直有延迟渲染 Deferred Rendering Unity5之后延迟光照 Light Pre-Pass / Deferred LightingUnity5之前分块延迟渲染Tile-Based Deferred RenderingUnity SRP渲染管线Forward即Tiled Forward Rendering分块正向渲染Unity SRP渲染管线群组渲染 Clustered Rendering Unity SRP渲染管线
等有时间和精力随着新技术的发展会更加完善本篇文章。 本文参考以下几篇大神的文章
https://blog.csdn.net/poem_qianmo/article/details/77142101
https://www.cnblogs.com/polobymulberry/p/5126892.html