一、渲染路径
1.渲染路径
渲染路径(Rendering Path)
决定光照的实现方式,当前渲染目标使用光照的流程。
二、渲染方式
1.前向渲染
在渲染每一帧时,每个顶点/片元都要执行一次片元着色器代码,这时需要将所有的光照信息都传递到片元着色器中。虽然大部分情况下的光源都趋向于小型化,而其照亮的区域也不大,但即便是光源里这个像素所对应的世界空间中的位置很远,但计算光照时,还会把所有的光源都考虑进去。
待渲染几何体->顶点着色器->片元着色器->渲染目标
例如,物体受n个光源影响,那么在每个片元执行着色器代码时,都必须把这n个光源都传递进片元着色器中执行光照计算。
测试环境:
2021.1.19f
8盏点光源
关闭天空盒
相机底色设为黑色
其余全是默认设置
前向渲染(pixel light count = 4)
光照规则
- 规则一:最亮的几个光源会被实现为像素光照
- 规则二:然后最多4个光源会被实现为顶点光照
- 规则三:剩下的光源会被实现为效率较高的球面调谐(Spherical Hamanic),模拟光照
规则一补充:
- 最亮的那盏光一定是像素光照
- Light的Render Mode是important 的光一定是像素光照
- 如果规则一、二加起来的灯光小于Quality Setting里的Pixel Count(最大像素光照数量),那么从剩下的光源中找出最亮的几盏灯光,实现为像素光照
- 最后剩下的光源,按照规则2或者3
- 在base pass里执行一盏像素光、所有的顶点光和球面调谐光照,并且进行阴影计算。
- 其余的像素光每盏一个Additional Pass,并且这些pass里没有阴影计算。
- 场景中看到的阴影,全是base pass里计算出最亮那盏像素光的阴影,其他像素光是不计算阴影的。
Pixel Light Count设置位置
上图可以看出,有4盏像素光,4盏顶点光。
淡蓝色既有像素光也有顶点光,而远处的深蓝色什么光都没有,不清楚unity内部怎么平衡这个权重的。
先看下前向渲染的光照的渲染顺序(Pixel Light Count = 4)
此处为语雀视频卡片,点击链接查看:录制_2021_11_19_15_02_43_370.mp4
Pixel Light Count = 8
此处为语雀视频卡片,点击链接查看:录制_2021_11_19_15_07_31_377.mp4
2.延迟渲染(Deferred Rendering)
主要解决大量光照渲染的方案。
延迟渲染的实质,事先不要对迭代三角形做光照计算,而是先找出来你能看到的所有像素,再去迭代光照。直接迭代三角形的话,由于大量三角形你是看不到的,无疑是极大浪费。
将渲染过程拆分成两个渲染通路(pass)。
第一个pass成为几何处理通路。首先将场景渲染一次,获取到待渲染对象的各种几何信息存储到名为G-buffer缓冲区中,这些缓冲区将会在之后用作更复杂的光照计算。由于有深度测试,所以最终写入G-buffer中各个数据都是离摄像机最近的片元的几何属性,这意味着在最后G-buffer中的片元必定要进行光照计算的。
待渲染几何体->顶点着色器->MRT->光照计算->渲染目标
第二个pass成为光照处理通路。该pass会遍历所有G-buffer中的位置、颜色、法线等参数,执行一次光照计算。
延迟渲染图
测试环境和前向渲染一样。
可以看出延迟渲染(无论PixelLightCount为多少),和前向渲染(PixelLightCount = 当前最大像素光)渲染效果一致。
延迟渲染光照顺序(重新开了新场景懒得调光颜色了)
此处为语雀视频卡片,点击链接查看:录制_2021_11_19_16_05_05_164.mp4
注:当相机与灯光最大边界有一定距离时,会出现一个新的drawcall
第二个Pass用于LDR的转码,当相机组件的HDR选项关闭时,这个Pass就有用了
一个点光源的计算由两个DrawMesh组成,第二个就是我们绘制光源的pass,但第一个就不同了,第一个是draw就是用来限制渲染的范围的,可以看到用的shader是unity内置的,名字写的很清楚,其实就是通过模板缓冲区来规定范围,这样后面的第二个drawmesh(黄色),就只能在规定的mesh范围内渲染了,超出部分不会进行无用的计算。
参考链接:Unity里的延迟渲染_exclude_renderers-CSDN博客
各种G-buffer
3.不同渲染路径的优劣及特性
1.后处理方式不同
前向渲染需要深度信息进行后处理,前向渲染需要单独渲染出一张深度图。
延迟渲染可以直接拿到渲染过程中存储深度信息的G-buffer来进行计算。
2.着色计算不同(shader)
前向渲染分主次光源,延迟渲染所有光源都会被完全计算不分主次。
前向渲染流程:待渲染几何体->顶点着色器->片元着色器->渲染目标。
延迟渲染流程:待渲染几何体->顶点着色器->MRT->光照计算->渲染目标。
3.抗锯齿方式不同
前向渲染支持MSAA,但是延迟渲染对于MSAA的支持并不好,因为MSAA会提前对像素进行光栅化处理。
4.不同渲染路径的优劣
- 前向渲染优点
-
- 支持半透明渲染
- 支持使用多个光照pass
- 支持自定义光照计算方式
- 前向渲染缺点
-
- 光源数量对计算复杂度影响巨大
- 访问深度等数据需要额外计算
- 延迟渲染优点
-
- 大量光照场景优势明显
- 只渲染可见像素,节省计算量
- 对后处理支持良好
- 用更少的shader
- 延迟渲染缺点
-
- 对MSAA支持不友好
- 透明物体渲染存在问题
- 占用大量显存带宽
扩充别的光照算法:
参考链接:游戏引擎中的光照算法 - 知乎
三、其他
unity渲染路径设置(2019.4.8)
移动端优化
- 两个TBDR
-
- 一个是SIGGRAPH 2010上提出的,通过分块来降低带宽内存用量
- 一个是PowerVR基于手机GPU的TBR架构提出的,通过HSR减少overdraw
Other Render Path
- 延迟光照 (Light Pre-Pass / Deferred Lighting
-
- 减少G-buffer占用的过多开销,支持多种光照模型
- Forward+(即Tiled Forward Rendering,分块正向渲染)
-
- 减少带宽,支持多光源,强制需要一个preZ
- 群组渲染 Clustered Rendering
-
- 带宽相对减少,多光源下效率提升
参考链接:游戏引擎中的光照算法 - 知乎
MSAA
Rendering 13
不同Path下光源Shader编写
PreZ / Zprepass
延迟光照的具体的思路是:
1、渲染场景中不透明(opaque )的几何体。将法线向量n和镜面扩展因子(specular spread factor)m 写入缓冲区。这个n/m-buffer 缓冲区是一个类似 G-Buffer的缓冲区,但包含的信息更少,更轻量,适合于单个输出颜色缓冲区,因此不需要MRT支持。
2、渲染光照。计算漫反射和镜面着色方程,并将结果写入不同的漫反射和镜面反射累积缓冲区。这个过程可以在一个单独的pass中完成(使用MRT),或者用两个单独的pass。环境光照明可以在这个阶段使用一个 full-screen pass进行计算。
3、对场景中的不透明几何体进行第二次渲染。从纹理中读取漫反射和镜面反射值,对前面步骤中漫反射和镜面反射累积缓冲区的值进行调制,并将最终结果写入最终的颜色缓冲区。若在上一阶段没有处理环境光照明,则在此阶段应用环境光照明。
4、使用非延迟着色方法渲染半透明几何体。
具体的流程图可以展示如下:
相对于传统的 Deferred Render,使用 Light Pre-Pass 可以对每个不同的几何体使用不同 的 shader 进行渲染,所以每个物体的 material properties 将有更多变化。
这里我们可以看出对于传统的 Deferred Render,它的第二步是遍历每个光源,这样就增加了光源设置的灵活性,而 Light Pre-Pass第三步使用的其实是 forward rendering,所以可以对每mesh 设置其材质,这两者是相辅相成的,有利有弊。
另一个 Light Pre-Pass 的优点是在使用 MSAA 上很有利。虽然并不是 100%使用上了 MSAA(除非使用 DX10/11 的特性),但是由于使用了Z 值和 Normal 值,就可以很容易找到边缘,并进行采样。