[Unity] 渲染路径与光源

Unity的渲染路径以及更多不同类型的光源。

Unity的渲染路径:

渲染路径:

在Unity里,渲染路径(Rendering Path)决定了光照是如何应用到Unity Shader中的,如果想让Shader的光照计算正确执行,必须为Shader正确的选择和设置需要的渲染路径。

分类:

Unity支持多种类型的渲染路径,在Unity5.0前主要有三种:前向渲染路径(Forward Rendering Path),延迟渲染路径(Deferred Rendering Path)和顶点照明渲染路径(Vertex Lit Rendering Path)。在Unity5.0以后,顶点照明渲染路径已经被Unity抛弃(但目前仍然可以对之前使用了顶点照明渲染路径的UnityShader兼容),新的延迟渲染路径已经代替了旧的延迟渲染路径。

大多数情况下,一个项目只使用一种渲染路径,因此可以为整个项目设置渲染时的渲染路径。

Edit/Project Settings/Player/Other Settings/Rendering Path

如果希望使用多个渲染路径,可以在每个摄像机的渲染路径设置中设置该摄像机使用的渲染路径以覆盖Project Settings中的设置。

【图】

如果选择了Use Player Settings,那么这个摄像机会使用Project Settings中的设置;否则就会覆盖掉Project Settings中的设置。如果当前的显卡不支持所选择的渲染路径,Unity会自动使用更低一级的渲染路径。

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

前向渲染路径:

前向渲染路径是传统的渲染方式,也是我们最常用的一种渲染路径。

  1. 前向渲染路径的原理:

    每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:颜色缓冲区与深度缓冲区。我们利用深度缓冲来决定一个片元是否可见,如果可见就更新颜色缓冲区中的颜色值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Pass{
    for(each primitive in this model){
    for(each fragment covered by this primitive){
    if(failed in depth test){
    // 未通过深度测试,该片元不可见
    discard;
    }
    else{
    // 可见则进行光照计算
    float4 color = Shading(materialInfo,pos,normal,lightDir,viewDir);
    // 更新帧缓冲
    writeFrameBuffer(fragment,color);
    }
    }
    }
    }

    对于每个逐像素光照,我们都需要进行上面一次完整的渲染流程。如果一个物体在多个逐像素光源的影响区域内,那么该物体就需要执行多个Pass,每个Pass计算一个逐像素光源的光照结果,然后在帧缓冲中把这些光照结果混合起来得到最终的颜色值。

  2. Unity中的前向渲染

    在Unity中,前向渲染路径有三种处理光照的方式:逐顶点处理,逐像素处理,球谐函数(Spherical Harmonics)处理。而决定一个光源使用哪种处理模式取决于它的类型和渲染模式

    • 光源类型:该光源是平行光还是其他类型的光源
    • 光源的渲染模式:该光源是否是重要的(Important),决定是否将其当作逐像素光源处理。

    在前向渲染中,Unity会根据场景中各个光源的设置以及这些光源对物体的影响程度(距离物体远近,光源强度等)来对光源进行一个重要度排序。其中,一定数目的光源会按照逐像素的方式进行排序,最多有4个光源按照逐顶点的方式进行处理,剩下的光源可以按照SH方式处理:

    • 场景中最亮的平行光总是按照逐像素处理
    • 渲染模式被设置成Not Important的光源,会按逐顶点或者SH处理
    • 渲染模式被设置成Important的光源,会按逐像素处理
    • 如果以上规则得到的逐像素光源数量小于Quality Setting中的逐像素光源数量(Pixel Light Count),会有更多的光源以逐像素的方式进行渲染
  3. 前向渲染的光照计算细节:

    • 需要使用编译指令保证Unity可以为相应类型的Pass生成所有需要的Shader变种,这些变种会处理不同条件下的渲染逻辑:是否使用光照贴图,当前处理哪种光源类型,是否开启了阴影等。
    • Base Pass中的平行光默认是支持阴影的,而Additional Pass中渲染的光源在默认情况下是没有阴影效果的,即使在Light组件中设置了有阴影的Shadow Type,但可以在Additional Pass中使用#pragma multi——compile_fwdadd_fullshadows代替#pragma multi_compile_fwdadd编译指令,这会为点光源和聚光灯开启阴影效果,但需要在Unity内部使用更多的Shader变种。
    • 如果不在Additional Pass中开启混合模式,其渲染结果将会覆盖掉之前的渲染结果,通常情况下,混合模式选择Blend One One。
    • 对于前向渲染来说,一个Unity Shader通常会定义一个Base Pass以及一个Additional Pass。一个Base Pass仅会执行一次,而一个Additional Pass会根据影响该物体的其他逐像素光源的数目被多次调用,即每个逐像素光源会执行一次Additional Pass。
  4. 内置的光照变量和函数(前向渲染)

光照变量名称 类型 描述
_LightColor0 float4 该Pass处理的逐像素光源的颜色
_WorldSpaceLightPos0 float4 _WorldSpaceLightPos0.xyz是该Pass处理的逐像素光源的位置,如果该光源类型是平行光,则_WorldSpaceLightPos0.w = 0,其他类型为1
_LightMatrix0 float4x4 从世界空间到光源空间的变换矩阵,可以用于采样cookie和光强衰减(attenuation)纹理
unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0 float4 仅用于Base Pass。前四个非重要的点光源在世界空间内的位置。
unity_4LightAtten0 float4 仅用于Base Pass。存储了前四个非重要的点光源的衰减因子。
unity_LightColor half4[4] 仅用于Base Pass。存储了前四个非重要的点光源的颜色。
光照函数名 描述
float3 WorldSpaceLightDir(float4 v) 仅可用于前向渲染中。输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向。内部实现使用了UnityWorldSpaceLightDir函数,没有被归一化。
float3 UnityWorldSpaceLightDir(float4 v) 仅可用于前向渲染中。输入一个世界空间中的顶点位置,返回世界空间中从该点到光源的光照方向,没有被归一化。
float3 ObjSpaceLightDir(float4 v) 仅可用于前向渲染中。输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向,没有被归一化。
float3 Shade4PointLights(…) 仅可用于前向渲染中。计算四个点光源的光照,它的参数是已经打包进矢量的光照数据,通常是上述的光照变量,前向渲染通常会使用这个函数来计算逐顶点光照。

顶点照明渲染路径:

顶点照明渲染是对硬件配置要求最少、运算性能最高,但同时也是得到的效果最差的一种类型。它不支持那些逐像素才能得到的效果,例如阴影、法线映射、高精度的高光反射等。

  1. Unity中的顶点照明渲染:

    顶点照明渲染路径通常在一个Pass中就可以完成对物体的渲染,在这个Pass中,我们通过逐顶点处理的方式计算所有我们关心的所有光源对该物体的照明。这是Unity中最快速的渲染路径,并且具有最广泛的硬件支持。

  2. 可访问的内置变量和函数:

    如果我们只需要渲染其中两个光源对物体的照明,可以仅使用_LightColor0与_WorldSpaceLightPos0。如果影响该物体的光源数目小于8,那么数组中剩下的光源颜色会被设置成黑色。

内置变量名称 类型 描述
unity_LightColor half4[8] 光源颜色。
unity_LightPosition float4[8] xyz分量是视角空间中的光源位置,如果光源是平行光,那么z分量值为0,其他光源类型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 ShaderVertexLights(float4 vertex,float3 normal) 输入模型空间中的顶点位置和法线,计算四个逐顶点光源的光照以及环境光。内部实现实际上调用了ShaderVertexLightsFull函数。
Float3 ShaderVertexLightsFull (float4 vertex,float3 normal, int lightCount,bool spotLight) 输入模型空间中的顶点位置和法线,计算lightCount个光源的光照以及环境光,如果spotLight值为true,那么这些光源会被当作聚光灯来处理,虽然结果更精确,但计算更加耗时;否则按点光源处理。

延迟渲染路径:

  • 前向渲染的问题:当场景中包含大量实时光源的时候,前向渲染的性能会急速下降。多个影响范围相互重叠的光源为了得到最终的光照效果,会将该区域的每个物体执行多个Pass来计算不同光源对该物体的光照结果,然后在颜色缓存中把这些结果混合起来得到最终的光照。然而,每执行一个Pass都要重新渲染一次物体,这导致了重复计算。
  • 延迟渲染:利用颜色缓冲,深度缓冲以及额外的G-缓冲区,它存储了我们关心的表面的其他信息——法线,位置,用于光照计算的材质属性等。
  1. 延迟渲染的原理:

    延迟渲染主要运用了两个Pass:在第一个Pass中,我们不进行任何光照计算,而是仅仅计算哪些片元是可见的,这主要是通过深度缓冲技术来实现,当发现一个片元是可见的,我们就把它的相关信息存储到G缓冲区中,然后在第二个Pass中,我们利用G缓冲区的各个片元信息来进行真正的光照计算。

    延迟渲染使用的Pass数目通常就是两个,这跟场景中包含的光源数目没有关系——即延迟渲染的效率不依赖于场景的复杂度,而是和我们使用的屏幕空间大小有关。

  2. Unity中的延迟渲染:

    对于延迟渲染路径来说,它最适合在场景中光源数目很多、如果使用前向渲染会造成性能瓶颈的情况下使用。而且,延迟渲染路径中的每个光源都可以用逐像素的方式进行处理。

    • 缺点:

      • 不支持真正的抗锯齿(anti-aliasing)功能
      • 不能处理半透明物体
      • 对显卡有一定要求
    • 当使用延迟渲染时,我们需要提供两个Pass

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

      2. 第二个Pass用于计算真正的光照模型。这个Pass会使用上一个Pass中渲染的数据来计算最终的光照颜色,再存储到帧缓冲中。

        默认的G缓冲区包含了以下几个渲染纹理:

        • RT0:格式是ARGB32,RGB通道用于存储漫反射颜色,A通道没有被使用
        • RT1:格式是ARGB32,RGB通道用于存储高光反射颜色,A通道用于存储高光反射的指数部分
        • RT2:格式是ARGB2101010,RGB通道用于存储法线,A通道没有被使用
        • RT3:格式是ARGB32(非HDR)或ARGBHalf(HDR),用于存储自发光+lightmap+反射探针
        • 深度缓冲和模版缓冲
  3. 可访问的内置变量和函数:

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

选择哪种渲染路径:

关于四种渲染路径的Unity的官方文档

Unity的光源类型:

支持的光源类型:

  • 平行光
  • 点光源
  • 聚光灯
  • 面光源:(仅在烘焙时才可发挥作用)

具体介绍:

  1. 光源属性:位置,强度,方向,颜色,衰减

  2. 平行光:

    1. 照亮的范围没有限制
    2. 几何属性只有方向,且到所有点的方向都是一样的
    3. 没有衰减的概念
  3. 点光源:

    1. 照亮空间有限,由空间中的一个球体定义