渲染路径(Rendering Path)决定光照如何应用到shader中。简言之,Rendering Path就是当前渲染目标使用光照的流程。
渲染路径
什么是渲染路径(Rendering Path)
决定光照的实现方式。简言之,就是当前渲染目标使用光照的流程。
渲染方式
- 默认设置下,多个光源情况下两种不同渲染方式效果
前向/正向渲染-Forward Rendering
每个物体受每个光源的影响,复杂度O(m*n)
流程
- 流程:待渲染几何体 → 顶点着色器 → 片元着色器 → 渲染目标
- 在渲染每一帧的时,每一个顶点/片元都要执行一次片元着色器代码,这时需要将所有的光照信息传到片元着色器中
- 离某个像素所对应的世界空间的位置很远的光源(且影响范围不大),光照计算还是会将其考虑进去
- 一个像素常理来说不受某个光源影响,但还是将其加入这个光源的光照计算,且这个像素还不一定能通过深度测试,这就造成了一个很大浪费
- 但如果场景光源不多,且以烘焙光为主的场景,前向渲染是很容易实现的一种渲染方式
补充细节
-
Unity中多盏光源时绘制顺序(最亮的平行像素光,如果有 + 顶点光 + sh球谐光->叠加的像素光)
-
光源分类规则(Unity中)
- 最亮的几个光源会被实现为像素光照(可配置,Unity在project setting-Quality中)
- 最多四个光源会被实现为顶点光照
- 剩下的光源会实现为效率较高的球面调谐光照(Spherical Hamanic),这是一种模拟光照
-
细节
- 最亮的那盏光一定是像素光照
- Light的Render Mode是important的光一定是像素光照(试了下把所有光都设置为重要,即使超过了配置的最大像素光源数量也会实现为像素光)
- 如果前面的两条加起来的像素光照小于Quality Setting里的Pixel Light Count(最大像素光照数量),那么从剩下的光源中找出最亮的那几盏光源,实现为像素光照
- 在base pass里执行一盏像素光、所有的顶点光和球面调谐光照,并且进行阴影计算,还包括自发光和环境光
- 其余的像素光每盏一个Additional Pass,并且这些pass里默认情况下没有阴影计算,可通过汇编指令开启
-
如果一个物体受到n个光源影响,那么每个片元着色器执行代码时,都必须把n个光源传递给着色器中进行计算
延迟渲染-Deferred Rendering
先收集信息到缓冲中,最后根据信息着色计算,复杂度O(m+n)
什么是延迟渲染
-
主要用来解决大量光照渲染的方案
-
延迟渲染的实质是:
- 先不要做迭代三角形做光照计算,而是先找出来你能看到的所有像素,再去迭代光照
- 直接迭代三角形的话,由于大量三角形是看不到的,会造成极大的浪费
流程
-
流程为:待渲染几何体 → 顶点着色器 → MRT(多目标渲染) → 光照计算 → 渲染目标
-
过程可以拆分为两个pass
- 第一个pass:几何处理通路。
- 首先将场景渲染一次,获取到的待渲染对象的各种几何信息存储到名为G-buffer的缓冲区中,这些缓冲区用来之后进行更复杂的光照计算
- 由于有深度测试,所以最终写入G-buffer中的,都是离摄像机最近的片元的集合属性,这就意味着,在G-buffer中的片元必定要进行光照计算
- 第二个pass:光照处理通路
- 这个pass会遍历所有G-buffer中的位置、颜色、法线等参数,执行一次光照计算
- 第一个pass:几何处理通路。
细节补充
-
什么是G-buffer
- G-Buffer,全称Geometric Buffer ,译作几何缓冲区,它主要用于存储每个像素对应的位置(Position),法线(Normal),漫反射颜色(Diffuse Color)以及其他有用材质参数(尽量节省RT使用,特别是高分辨率,使用带宽会很多)
- 根据这些信息,就可以在像空间(二维空间)中对每个像素进行光照处理
- 一个典型的G-buffer
- UE4中默认使用延迟管线,在视图中显示缓冲总览
-
延迟渲染不支持透明物体的渲染
- 因为透明物体要关闭深度测试,对缓冲生成会有问题
- 延迟渲染使用前向渲染来渲染透明物体,基本和前向渲染透明物体流程一致
-
相当于把整个屏幕的信息绘制到一个图中,每个RT都可以写到一个G-buffer中,G-buffer中的数据都是2D的,所以我们的光照计算就相当于一个2D的光照后处理
不同渲染路径的特性
后处理方式不同
- 比如实现深度雾,需要深度信息
- 前向渲染需要单独渲染出一张深度图
- 延迟渲染直接用G-buffer中的深度信息计算即可
着色计算不同(shader)
- 延迟渲染
- 因为是最后统一计算光照的,所以只能算一个光照模型(如果需要其他光照模型,只能切换pass)
- 在G-Buffer中也不知道哪个像素是哪个mesh的(除非额外记录)
抗锯齿方式不同
- 延迟渲染不能用MSAA,毕竟用来多重采样的信息没有通过测试。但如今FXAA和TAA效果都挺好的
不同渲染路径的优劣
前向渲染
优点
- 支持半透明渲染
- 支持使用多个光照pass
- 支持自定义光照计算方式
- 延迟渲染是渲染到Gbuffer,再一起计算光照,所以不支持每一个物体用单独的光照方式计算)
缺点
- 光源数量对计算复杂度影响巨大
- 访问深度等数据需要额外计算(需要再渲染一张深度图)
延迟渲染
优点
- 大量光照场景的情况下,性能有明显优势
- 只渲染可见像素,节省计算量
- 对后处理支持良好(例如深度信息:直接拿G-buffer中的就行)
- 用更少的shader(所有的物体光照模型都一样,很多东西不用再定义了)
缺点
-
对MSAA支持不友好
-
透明物体渲染存在问题(深度问题,只渲染力物体最近的物体,渲染透明度时会出现问题)
-
占用大量的显存带宽
- 涉及一个clear的操作,如果不清理的话,后边可以继续获取到
- 每一帧都需要几张rt在显存中传输、清理等,会更耗带宽
-
只能使用同一个光照pass
其他部分
渲染路径的设置
移动端优化TBDR
第一种定义
- 在SIGGRAPH2010提出,作为传统Defferred Rendering的另一种主要改进,分块延迟渲染(Tile-Based Deferred Rendering,TBDR)旨在合理分摊开销(amortize overhead),自SIGGRAPH 2010上提出以来逐渐为业界所了解。基于延迟渲染的优化方式,通过分块来降低带宽内存用量(解决带宽和内存问题),以及功耗相关
- 延迟渲染的分块,把整个图像分为很多块,再一块一块的渲染
第二种定义
- PowerVR基于手机GPU的TBR框架提出的改进,通过HSR减少Overdraw
- TBDR这个架构是PowerVR提出来的对TBR的一次改进,在TBR的基础上再加了一个Deferred
- 通过做一些可见性测试来减少Overdraw
- 涉及手机GPU架构,和延迟渲染没什么关系
- 这篇文章讲的比较详细https://zhuanlan.zhihu.com/p/259760974
其他渲染路径
延迟光照(Light Pre-Pass / Deferred Lighting)
- 减少G-buffer占用的过多开销,支持多种光照模型
- 和延迟渲染的区别:
- 用更少的buffer信息,着色计算的时候用的是forward,所以第三步开始都是前向渲染(可以对不同的物体进行不同的光照模型)
Forward+(即Tiled Forward Rendering,分块正向渲染)
- 减少带宽,支持多光源,强制需要一个preZ
- 通过分块索引的方式,以及深度和法线信息来到需要进行光照计算的片元进行光照计算
- 需要法线和深度的后处理需要单独渲染一个rt出来
- 强制使用了一个preZ(如果没涉及过这个概念的话,可以理解为进行了一个深度预计算)
群组渲染(Clustered Rendering)
- 带宽相对减少,多光源下效率提升
- 分为forward和deferred两种
不同path下光源shader 的编写
更详细的还是要看官方文档
PreZ(Zprepass)
-
实际上就是一个深度计算
-
和深度图的区别
- 都是深度信息
- PreZ是用一个pass,只算深度
- 深度图是算成了一张RT(RenderTexture),把深度信息绘制到了一张RT上
- 具体用途:
- 大规模草、透明排序会用到PreZ
- 都是深度信息
-
early-z 和 PreZ的区别
- early-z,自动的,对面数有要求(硬件自动)
- PreZ,当early-z失效的时候,或者需要深度图的时候,一种手动代替的方案
参考链接
- https://zhuanlan.zhihu.com/p/79100589
- https://zhuanlan.zhihu.com/p/102134614
- https://zhuanlan.zhihu.com/p/28489928
- https://zhuanlan.zhihu.com/p/259760974
- https://www.3dgep.com/forward-plus/#Forward
- https://gamedevelopment.tutsplus.com/articles/forward-rendering-vs-deferred-rendering–gamedev-12342
- 大佬笔记
作业
延迟渲染管线的优化(移动端)
这里就放几篇参考文章,有更多感悟时回来总结