Chapter9_光照

渲染路径(Rendering Path)

渲染路径决定了光照如何应用到Shader中,决定了把光源信息和处理后的光照信息放到那些数据中。

全局渲染路径设置(Edit->ProjectSetting->Graphics)
单个摄像机设置渲染路径

四种渲染路径设置 :

  • Deferred(延迟渲染)
  • Forward(前向渲染)
  • Legacy Vertex Lit(遗留顶点照明渲染)
  • Legacy Deferred(light prepass)(遗留延迟渲染)

Unity会优先执行Shader中符合当前渲染路径的Pass,例如设置了Deferred(延迟渲染)。

  1. 优先执行Shader中Pass的LightMode为Deferred(延迟渲染)路径的Pass。
  2. 如果没有符合条件的Pass,寻找低一级Shader中Pass的LightMode为Forward(前向渲染)路径的Pass。
  3. 如果没有符合条件的Pass,寻找低一级Shader中Pass的LightMode为Legacy Vertex Lit(遗留顶点照明渲染)路径的Pass。

Shader在同一时间内,只会执行一个渲染路径下的Pass。

Shader指定某个Pass使用什么渲染路径,通过标签LightMode设置。

标签 描述
Always 不管使用什么渲染路径,该Pass都会被渲染,但不会计算任何光照
ForwardBase 用于前向渲染,该Pass会计算环境光,最重要的平行光,逐顶点/SH光源和Lightmaps
ForwardAdd 用于前向渲染,该Pass会计算额外的逐像素光源,每个Pass对应一个光源
Deferred 用于延迟渲染,该Pass会渲染G缓冲(G-buffer)
ShadowCaster 把物体的深度信息渲染到阴影映射纹理或一张深度纹理中
PrepassBase 用于遗留的延迟渲染,该Pass会渲染法线和高光反射的指数部分
PrepassFinal 用于遗留的延迟渲染,该Pass通过合并纹理,光照和自发光来渲染得到最后的颜色
Vertex,VertexLMRGBM,VertexLM 用于遗留的顶点照明渲染

当Shader中有"LightMode" = "Always"时:

  1. 当Shader中只有 "LightMode" = "Always"的Pass时,Shader中所有Pass无论在什么渲染路径下都按先后顺序执行。
  2. 当Shader处于Deferred(延迟渲染)路径下时候,Shader中的"LightMode" = "Always"的Pass不被执行。
  3. 当Shader处于Forward(前向渲染),和Legacy Vertex Lit(遗留顶点照明渲染)渲染路径下时,含有"LightMode" = "Always"的Pass的Shader,会根据Shader中其他Pass是否能在当前渲染路径下执行来决定"LightMode" = "Always"的Pass是否能被执行。如果其他Pass有能够执行的,"LightMode" = "Always"的Pass也能被执行。如果其他所有Pass不能被执行, "LightMode" = "Always"的Pass也不能被执行。 所有能执行的Pass会根据前后顺序执行,Shader中"LightMode" = "Always"的Pass之外的所有Pass都不执行,那"LightMode" = "Always"的Pass也不被执行。

Unity5.x后如果设置了前向渲染路径,Pass没有设置LightMode标签,就会被当做Legacy Vertex Lit(遗留顶点照明渲染)等同的Pass。


前向渲染路径

1.前向渲染路径原理

每进行一次完成的前向渲染,需要在一个Pass中渲染图元,并计算两个缓冲区。深度缓冲区决定片元是否可见,可见就更新颜色缓冲区颜色值。
对于每个逐像素光源,都需要一个Pass计算光照。一个物体如果受M个光源影响,就需要执行M个Pass,然后在帧缓冲中把这些光照结果混合得到最终颜色。如果一个场景有N个模型,每个模型受到M个光源影响,渲染这个场景需要 N * M 个Pass。因此渲染引擎会限制每个物体的逐像素光照数目。

2.Unity中的前向渲染

Unity中前向渲染有3中处理光照的方式:

  • 逐顶点处理
  • 逐像素处理
  • 球谐函数处理

光源的类型和渲染模式决定了它被怎么处理。

  • 光源类型是指该光源是平行光还是其他类型光源。
  • 光源渲染模式是指该光源Render Mode属性

Pixel Light Count数量(Quality Setting)的光源会按逐像素处理,然后最多四个光源按逐顶点处理,剩下的按SH方式处理。

  • 场景中最亮的平行光总是按逐像素处理
  • Render Mode被设置成Not Important的光源,按逐顶点或SH处理。
  • Render Mode被设置成Important的光源,按逐像素处理。
  • 根据以上规则,逐像素光源大于Pixel Light Count数量(Quality Setting),光源会被当做逐顶点或SH方式处理。
  • 最亮的平行光Render Mode被设置为Not Important一样会被当做逐顶点或SH方式处理。

前向渲染有两种Pass:

  1. Base Pass(LightMode = "ForwardBase")     
  2. AdditionPass(LightMode = "ForwardAdd")

Unity前向渲染(LightMode = ForwardBase/ForwardAdd)内置光照变量和函数 :

变量名称 类型 描述
_LightColor0 float4 该Pass处理的逐像素光源的颜色
_WorldSpaceLightPos0 float4 该Pass处理的逐像素光照位置。如果_WorldSpaceLightPos0.w = 0,表示该光源是平行光,_WorldSpaceLightPos0.xyz是平行光的方向向量,反之表示光源为点光源,_WorldSpaceLightPos0.xyz为光源的世界坐标
_LightMatrix0 float4x4 从世界空间到光源空间的变换矩阵,可以用于采样cookie和光强衰减纹理

unity_4LightPosX0

unity_4LightPosY0

unity_4LightPosZ0

float4 仅用于Base Pass,前4个非重要的点光源在世界空间中的位置
unity_4LightAtten0 float4 仅用于Base Pass,存储了前4个非重要的点光源的衰减因子
unity_LightColor half[4] 仅用于Base Pass,存储了前4个非重要的点光源的颜色
函数名 描述
float3 WorldSpaceLightDir(float4 v) 仅可用于前向渲染,输入一个模型空间的顶点位置,返回世界空间中从该点到光源的光照方向。内部实现使用了UnityWorldSpaceLightDir函数,没有归一化。
float3 UnityWorldSpaceLightDir(float4 v) 仅可用于前向渲染,输入一个世界空间下的顶点位置,返回世界空间中从该点到光源的光照方向,没有被归一化。
float3 ObjSpaceLightDir(float4 v) 仅可用于前向渲染,输入一个模型空间下的顶点位置,返回模型空间中从该点到光源的光源方向,没有被归一化。
float3 Shade4PointLights(...) 仅可用于前向渲染,计算四个点光源的光照。它的参数是已经内置的光照数据。通常就像上表的 unity_4LightPosX0,  unity_4LightPosY0

unity_4LightPosZ0,unity_4LightAtten0,unity_LightColor等等。

通常使用这个函数计算逐顶点的光照

顶点照明渲染路径

通常只使用一个Pass(LightMode = Vertex),进行逐顶点光照计算。

顶点照明渲染中,最多可以计算8个逐顶点光源的光照。

顶点照明渲染路径中可用的内置变量和函数

变量名称 类型 描述
unity_LightColor half4[8] 光源颜色(如果某个物体所受光照小于8个,剩余的光源颜色为黑色。)
unity_LightPosition float4[8]

如果光源是平行光,-xyz分量是视角(相机)空间中的光源方向,z分量值为0。其他光源类型xyz分量是视角空间中的光源位置,其他光源类型为z分量值为1.

unity_LightAtten half4[8] 光源衰减因子,如果光源是聚光灯,x分量是cos(spotAngle/2),y分量是1/cos(spotAngle/4);如果是其他类型的光源,x分量是-1,y分量是1。z分量是衰减的平方,w分量是光源范围开根号的结果。
unity_SpotDirection float4[8] 如果光源是聚光灯,值为视角空间的聚光灯的位置。如果是其他类型的光源,值为(0,0,1,0)
函数名 描述
float3 ShadeVertexLights(float4 vertex,float3 normal) 输入模型空间中的顶点位置和法线,计算四个逐顶点光源的光照以及环境光。内部实现实际上调用了ShadeVertexLightsFull函数
float3 ShadeVertexLightsFull(float4 vertex,float3 normal,int lightCount,bool spotLight) 输入模型空间中的顶点位置和法线,计算lightCount个光源的光照以及环境光。如果spotLight值为true。那么这些光源会被当做聚光灯处理。虽然结果更精确,但是计算更加耗时。否则按点光源处理。

延迟照明渲染路径(移动设备不支持)

当场景中包含大量实时光源时,前向渲染性能急速下降,这时候就可以使用延迟渲染路径。除了前向渲染使用的颜色缓冲区和深度缓冲区外,延迟渲染还会利用额外的G缓冲区。G缓冲区存储了表面法线,位置等用于光照计算的材质属性等。

1.延迟渲染原理

  • Pass1(不进行光照计算,通过深度缓冲,计算片元可见性)

把物体的漫反射颜色,高光反射颜色,平滑度,法线,自发光和深度等信息渲染到屏幕空间的G缓冲区中。对于每个物体,这个Pass只会执行一次。

  • Pass2(将Pass1存储到G缓冲区中可见片元,取出计算光照)

取出Pass1存到G缓冲区中的片元信息,计算光照,得到最终光照颜色。再存到帧缓冲区。

延迟渲染效率跟场景中光源数量没关系。而和我们的屏幕空间大小有关。我们需要的信息都存储在G缓冲区中,而缓冲区可以理解成一张张2D图片。屏幕越大,计算越耗时。

2.Unity中延迟渲染

Unity5.x之前使用遗留的的延迟渲染路径。Unity5.x之后使用延迟渲染路径。

延迟渲染缺点:

  • 不支持真正的抗锯齿功能
  • 不能处理半透明物体
  • 对显卡有要求

3.G缓冲区的渲染纹理

  • RT0: 格式ARGB32,RGB存储漫反射颜色,A通道没使用。
  • RT1: 格式ARGB32,RGB存储高光反射颜色,A通道存储高光反射的指数部分。
  • RT2: 格式ARGB2101010,RGB存储法线,A通道没使用。
  • RT3: 格式ARGB32(非HDR)或 ARGBHalf(HDR),存储自发光+lightmap+反射探针。
  • 深度缓冲和模板缓冲

4.延迟渲染路径可访问内置变量和函数

名称 类型 描述
_LightColor float4 光源颜色
_LightMatrix0 float4x4 从世界空间到光源空间的变换矩阵,可以用于采样cookie和光前衰减纹理

4个渲染路径对比

特性 延迟渲染路径 正向渲染路径 传统延迟渲染 传统顶点光照
逐像素照明(法线贴图、light cookie) x
实时阴影 有注意事项 x
反射探头(Reflection Probe) x x
深度和法线缓冲区 额外的渲染通道pass x
Soft Particles x x
半透明物体 x x
抗锯齿 x x
Light Culling Masks Limited Limited
光照保真度 所有 per-pixel 一些 per-pixel 所有 per-pixel 所有 per-vertex

实践:1.前向渲染路径

Shader "Chan/Chapter9_ForwardRendering" {
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(8.0,256)) = 20
    }
    SubShader
    {
        //Base Pass
        Tags{"RenderType" = "Opaque"}
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            
            //保证光照衰减等光照变量可以被正确赋值
            #pragma multi_compile_fwdbase
            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
  &
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值