着色器用于定义对象的外观(材质属性)以及它对光的反应,因为必须在着色器中构建光照计算,然而可能会存在很多类型的光影,所以编写Shader是非常麻烦的一件事。Unity为了简化编写Shader的操作,提供了Surface Shaders,它会将所有的光照,阴影,光照贴图,向前渲染和延迟渲染都会自动处理。
如何选择渲染通道(Pass)以及灯光如何应用,都取决于采用什么样的渲染路径。Shaer中的每个Pass适用于什么样的渲染路径都是通过PassTags中的LightMode 来定义的。
Unity中包含的渲染路径有:
渲染路径 | 支持的LightMode |
---|---|
Forwawrd Rendering(正向渲染) | ForwardBase和ForwardAdd Pass会被使用 |
Deferred Shading(延迟着色) | Deferred Pass会被使用 |
legacy Deferred Lighting(遗留 延迟光照) | PrepassBase和PrepassFinal Pass会被使用 |
legacy Vertex Lit(遗留 顶点光照) | Vertex,VertexLMRGBM和VertexLM Pass 会被使用 |
上述任何一个渲染路径,为了渲染阴影或深度纹理,ShadowCaster Pass会被使用 |
Forward Rendering path(正向渲染路径):
在Forward Rendering 路径中,在影响对象的所有灯光中,一些最亮的灯会以逐像素的方式进行照明,然后会有4个灯光以逐顶点的方式进行照明,剩余的灯光会以SH(球面谐波)的方式进行渲染。主要规则如下:
1.将渲染模式设置为"Not Important"的灯始终是按顶点或者SH进行渲染
2.最亮的平行光会以逐像素的方式进行渲染。
3.将渲染模式设置为“Important”的灯始终为逐像素进行渲染。
4.最多会有4个光源按照逐顶点的方式进行渲染
5.经过以上操作后,如果逐像素渲染的灯光个数小于Quality Setting设置中Pixel Light Count的数量话,会按照亮度从高到低的顺序,选择合适的灯光数量,进行逐像素渲染。
渲染流程如下:
1.Forward Base Pass 会执行最亮的逐像素平行光和所有的逐顶点/SH灯光渲染。
2.Forward Add Pass 会在每个逐像素灯光(除逐像素平行光以外的)进行一次渲染。
例如:
上图中,对象(圆圈)受到灯光A到H的影响,假设A到H都具有相同的颜色和强度,且所有灯光都具有自动渲染模式,所以他们将按照与对象距离来进行排序,前面的灯光会以逐像素的方式进行渲染(A-D,具体数量会根据质量设置中的数据来设置),然后就是以逐顶点的灯光渲染(D-G,最到4个灯光),剩余的灯光会以SH(G-H)的方式进行渲染。如图:
注意,在不同的模式渲染中有重叠渲染的部分,这样当物体和光线移动时,不会出现太多的"灯光跳跃"
除A灯光外,其余逐像素渲染灯光会调用Forward Add Pass。
ForwardBase :使用一个逐像素平行光和所有SH/顶点光源渲染对象,在此过程中还会添加着色器中的光照贴图,环境光和自发光。在此渲染过程中方向光可以具有阴影(注意光照贴图对象不会从SH灯获取照明)。
如果在Pass中使用了“OnlyDirectional”标签,ForwardBase 通道仅渲染主方向光,环境/光探测器和光照贴图(SH和顶点光不包括在Pass数据中)。
ForwardAdd :会为所有影响该对象的逐像素光源渲染一次(除主平行光外) 。默认情况下,这些过程中的灯光是没有阴影的,除非使用了multi_compile_fwdadd_fullshadows这样的编译指令,来生成多个着色器程序变体。
如果着色器没有提供适当的Pass(即没有ForwardBase也不存在ForwardAdd),则该对象的渲染方式语Vertex Lit 路径中的渲染方式相同。
SH(球面谐波)的渲染速度是非常块的,并且在CPU上的成本很低,实际上可以自由地应用GPU(ForwardBase通道总是计算SH照明,由于SH的工作方式,所以无论多少SH灯,成本都是一样的)。
SH的缺点有:
1.它们是在顶点的基础上进行计算,所以不支持Cookie和法线贴图
2.SH照明频率很低,无法有明显的照明过度。也只影响漫反射光照(镜面高管的频率太低)。
3.SH照明不是局部的,靠近某些表面的球谐函数点光源或聚光灯会看起来有些别扭。
Deferred shading Rendering path(延迟着色渲染路径):
使用Deferred shading 时,对可影响GameObject的灯光数量没有限制,所有灯光都会按逐像素的方式评估光照,所以它们可以与法线题图等正确交换,所有的灯光都可以有Cookie和阴影。
Deferred shading 的优点:
照明的处理开销与光照的像素数量成正比,这是由场景中光的大小决定,而不是它照亮了多少游戏物体,因此可以通过保持较小的光线来提高性能。
延迟着色也具有高度一致和可预测的行为,每个光的效果都是按像素计算的,因此没有在大三角形上分解的光照计算。
Deferred shading 的缺点:
延迟照明没有真正的抗锯齿支持,也无法处理半透明的GameObject(这些是使用Forward Rendering渲染的)。
Mesh Render(网格渲染器)和Receive Shadows(接收阴影)标志也不支持。
剔除遮蔽图的支持方式有限(最多可以使用四个剔除遮蔽图,即:剔除层遮蔽图必须至少包含减去 4 个任意层后的所有层,所以 32 层中必须设置 28 层。否则会得到图形假象。)。
使用要求:
1.需要具有多个渲染目标(MRT)的显卡,Shader Model 3.0(或以上)的图形卡,并支持深度渲染纹理。2006年后大多数pc显卡都支持延迟着色,从GeForce 8xxx,Radeon x2400,Intel G45开始。
2.移动设备上不支持,主要由于使用MRT格式(某些GPU支持多个渲染目标,但只支持非常有限的位数)。
3.使用正交投影时,不支持延迟渲染。如果相机的投影模式设置为'Orthographic(正交)',则相机会退回到“Forward Rdndering”。
性能:
延迟着色中的实时光的渲染开销与光照像素的数量成正比,与场景复杂度无关,所以小的点光等和聚光灯在性能上更有优势。如果它们被场景游戏对象完全或部分遮挡,可能会获得更好的效果。
有阴影的灯光比没有的阴影的灯要耗费的性能更多,在延迟渲染中,阴影投射的游戏对象仍然需要为每个阴影投射光渲染一次或多次。此外,应用阴影的光照着色器比禁用阴影时使用的渲染开销更高。
细节:
使用延迟渲染着色时,Unity中的渲染过程分为两步:
G-buffer Pass:游戏对象被渲染成具有漫反射色、高光色、平滑度、世界空间法线、发射和深度的屏幕空间缓冲器。
Lighting Pass:先前生成的缓冲区用于将照明添加到发射缓冲区。
不能处理延迟渲染的着色(物体),在该过程完成后会使用Forward Rendering 路径进行渲染。
默认g-buff布局:
RT0,ARGB32格式:漫反射颜色(RGB),遮挡(A)。
RT1,ARGB32格式:镜面反射颜色(RGB),粗糙度(A)。
RT2,ARGB2101010格式:世界空间标准(RGB),未使用(A)。
RT3,ARGB2101010(非HDR)或ARGBHalf(HDR)格式:Emission+lighting+lightmaps+reflectin 侦探 缓冲。
深度+模板缓冲区。
默认的g缓冲区布局时160位/像素(非HDR)或192位/像素(HDR)。
相机不使用HDR时,Emission+lighting缓冲区(RT3)以对数方式编码,以提供比ARGB32纹理通常可能的更大的动态范围。
注意,相机使用HDR渲染时,没有为Emission +光照缓冲区(RT3)创建单独的渲染目标; 相反,Camera渲染的渲染目标(即传递给图像效果的渲染目标)用作RT3。
G-Buffer Pass:
渲染每个Gameobject一次,漫反射和镜面反射颜色,表面平滑度,世界空间法线和发射+环境+反射+光照贴图渲染为g缓冲区纹理。g-buffer纹理被设置为全局着色器属性,以供稍后访问着色器
Lighting Pass:
照明通过基于g缓冲区和深度计算照明。照明是在屏幕空间中计算的,因此处理时间与场景复杂度无关。灯光会被添加到emission 缓冲区中。
不穿过相机近平面的点光源和聚光灯会渲染为3D形状,并启用Z缓冲区对场景的测试,这使得部分或完全遮挡得点光灯和聚光灯非常块快得渲染。穿过近平面得定向灯和点/聚光灯呈现为全屏四边形。
如果灯光开启了阴影,那么它们也会在此过程中渲染并应用,阴影并不是“免费”出现的。需要渲染阴影投射器并运用更加复杂的光线着色器。
唯一可用的照明模型是 Standard,如果需要不同的模型,可以修改光照通道着色器,将内置着色器中的Internal-DeferredShading.sharder 文件的修改版本放入Asset/Resources文件夹中,然后在Edit/Project Settings/Graphics 窗口中将“Deferred”修改为“Custom Shader”,然后更改这个在使用的着色器选项。
Legacy Deferred Lighting Rendering Paht(旧版延迟光照渲染路径):
与Deferred shadering 相似,从Unity5.0 版本以后被认为是传统功能,因为他不支持某些渲染功能(如标准着色器,反射探测器等)。
使用延迟光照时,Unity中的渲染过程会分为3步:
1.Base Pass:渲染对象以生成具有深度,法线和镜面反射功率的屏幕空间缓冲区。
2.Light Pass:使用前面生成的缓冲区用于计算照明到另一个屏幕空空间缓冲区(唯一可用的照明模型为Blinn-Phong)。
3.Final Pass:再次渲染对象。它们获取计算出的光照,将其与颜色纹理相结合,并添加任何环境/发光照明。
Vertex Lit Rendering Path (顶点照明路径):
Vertex Lit路径通常在一次通过中渲染每个对象,并在对象顶点出计算所有光源的光照。
Vertex Lit是最快的渲染路径,并且具有最广泛的硬件支持(不使用与控制台)。
由于所有的光照都是在顶点级别计算的,因此此渲染路径不支持大多数逐像素效果:不支持阴影,法线贴图,cookie和非常细腻的镜面高光。