Shaderlab Notizen 7-2 Standard Shader

五、Standard Shader中正向基礎(chǔ)渲染通道源碼

Standard Shader正向渲染基礎(chǔ)通道(Shader Model 3.0版)的Shader源代碼:

//------------------------------------【子著色器1】------------------------------------
// 此子著色器用于Shader Model 3.0
//----------------------------------------------------------------------------------------
SubShader
{
    //渲染類型設(shè)置:不透明
    Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }

    //細(xì)節(jié)層次設(shè)為:300
    LOD 300

    //--------------------------------通道1-------------------------------
    // 正向基礎(chǔ)渲染通道(Base forward pass)
    // 處理方向光,自發(fā)光,光照貼圖等 ...
    Pass
    {
        //設(shè)置通道名稱
        Name "FORWARD"

        //于通道標(biāo)簽中設(shè)置光照模型為ForwardBase,正向渲染基礎(chǔ)通道
        Tags { "LightMode" = "ForwardBase" }

        //混合操作:源混合乘以目標(biāo)混合
        Blend [_SrcBlend] [_DstBlend]
        // 根據(jù)_ZWrite參數(shù),設(shè)置深度寫入模式開關(guān)與否
        ZWrite [_ZWrite]

        //===========開啟CG著色器語(yǔ)言編寫模塊===========
        CGPROGRAM

        //著色器編譯目標(biāo):Model 3.0
        #pragma target 3.0

        //編譯指令:不使用GLES渲染器編譯
        #pragma exclude_renderers gles

        // ---------編譯指令:著色器編譯多樣化--------
        #pragma shader_feature _NORMALMAP
        #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
        #pragma shader_feature _EMISSION
        #pragma shader_feature _METALLICGLOSSMAP
        #pragma shader_feature ___ _DETAIL_MULX2
        #pragma shader_feature _PARALLAXMAP
//這邊定義了很多的“宏”、 _NORMALMAP、_ALPHATEST_ON、_ALPHABLEND_ON、_EMISSION、_METALLICGLOSSMAP、_DETAIL_MULX2、_PARALLAXMAP,在頂點(diǎn)和片段著色器實(shí)現(xiàn)部分,可以用#ifdef _EMISSION類似的宏命令來對(duì)不同情況下的實(shí)現(xiàn)進(jìn)行區(qū)別對(duì)待。

        //--------著色器編譯多樣化快捷指令------------
        //編譯指令:編譯正向渲染基礎(chǔ)通道(用于正向渲染中,應(yīng)用環(huán)境光照、主方向光照和頂點(diǎn)/球面調(diào)和光照)所需的所有變體。
        //這些變體用于處理不同的光照貼圖類型、主要方向光源的陰影選項(xiàng)的開關(guān)與否
        #pragma multi_compile_fwdbase
        //編譯指令:編譯幾個(gè)不同變種來處理不同類型的霧效(關(guān)閉/線性/指數(shù)/二階指數(shù)/)
        #pragma multi_compile_fog

        //編譯指令:告知編譯器頂點(diǎn)和片段著色函數(shù)的名稱
        #pragma vertex vertForwardBase
        #pragma fragment fragForwardBase
        //指明了這個(gè)pass中頂點(diǎn)著色函數(shù)和片段著色函數(shù)分別是名為vertForwardBase和fragForwardBase的函數(shù)

        //包含輔助CG頭文件
        #include "UnityStandardCore.cginc"
        //vertForwardBase和       fragForwardBase的函數(shù)全都定義于此“UnityStandardCore.cginc”頭文件中
        //===========結(jié)束CG著色器語(yǔ)言編寫模塊===========
        ENDCG
    }
……
}

5.1 頂點(diǎn)著色函數(shù)vertForwardBase
源碼如下:

//-----------------------------------【vertForwardBase函數(shù)】---------------------------
//  用途:正向渲染基礎(chǔ)通道的頂點(diǎn)著色函數(shù)
//  說明:實(shí)例化一個(gè)VertexOutputForwardBase結(jié)構(gòu)體對(duì)象,并進(jìn)行相應(yīng)的填充
//  輸入:VertexInput結(jié)構(gòu)體
//  輸出:VertexOutputForwardBase結(jié)構(gòu)體
//  附:VertexInput結(jié)構(gòu)體原型:
/*
struct VertexInput
{
    float4 vertex   : POSITION;
    half3 normal    : NORMAL;
    float2 uv0      : TEXCOORD0;
    float2 uv1      : TEXCOORD1;
    #if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META)
    float2 uv2      : TEXCOORD2;
    #endif
    #ifdef _TANGENT_TO_WORLD
    half4 tangent   : TANGENT;
    #endif
};
*/
//---------------------------------------------------------------------------------------------------------
VertexOutputForwardBase vertForwardBase (VertexInput v)
{
    //【1】實(shí)例化一個(gè)VertexOutputForwardBase結(jié)構(gòu)體對(duì)象
    VertexOutputForwardBase o;
    //用Unity內(nèi)置的宏初始化參數(shù)
    UNITY_INITIALIZE_OUTPUT(VertexOutputForwardBase, o);

    //【2】通過物體坐標(biāo)系到世界坐標(biāo)系的變換矩陣乘以物體的頂點(diǎn)位置,得到對(duì)象在世界坐標(biāo)系中的位置
    float4 posWorld = mul(_Object2World, v.vertex);

    //【3】若定義了鏡面立方體投影宏,將計(jì)算得到的世界坐標(biāo)系的xyz坐標(biāo)作為輸出參數(shù)的世界坐標(biāo)值
    #if UNITY_SPECCUBE_BOX_PROJECTION
        o.posWorld = posWorld.xyz;
    #endif

    //【4】輸出的頂點(diǎn)位置(像素位置)為模型視圖投影矩陣乘以頂點(diǎn)位置,也就是將三維空間中的坐標(biāo)投影到了二維窗口
    o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    //【5】計(jì)算紋理坐標(biāo),使用UnityStandardInput.cginc頭文件中的輔助函數(shù)。
    o.tex = TexCoords(v);
    //【6】視線的方向= 對(duì)象在世界坐標(biāo)系中的位置減去攝像機(jī)的世界空間位置,并進(jìn)行逐頂點(diǎn)歸一化
    o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos);

    //【7】計(jì)算物體在世界空間中的法線坐標(biāo)
    float3 normalWorld = UnityObjectToWorldNormal(v.normal);

    //【8】進(jìn)行世界空間中的切線相關(guān)參數(shù)的計(jì)算與賦值
    //若定義了_TANGENT_TO_WORLD
    #ifdef _TANGENT_TO_WORLD
        //世界空間中的物體的法線值
        float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
        //在世界空間中為每個(gè)頂點(diǎn)創(chuàng)建切線
        float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w);
        //分別為3個(gè)分量賦值
        o.tangentToWorldAndParallax[0].xyz = tangentToWorld[0];
        o.tangentToWorldAndParallax[1].xyz = tangentToWorld[1];
        o.tangentToWorldAndParallax[2].xyz = tangentToWorld[2];
    //否則,三個(gè)分量直接取為0,0和上面計(jì)算得到的normalWorld
    #else
        o.tangentToWorldAndParallax[0].xyz = 0;
        o.tangentToWorldAndParallax[1].xyz = 0;
        o.tangentToWorldAndParallax[2].xyz = normalWorld;
    #endif

    //【9】陰影的獲取
    TRANSFER_SHADOW(o);

    //【10】進(jìn)行頂點(diǎn)正向相關(guān)的全局光照操作
    o.ambientOrLightmapUV = VertexGIForward(v, posWorld, normalWorld);

    //【11】若定義了_PARALLAXMAP宏,則計(jì)算視差的視角方向并賦值
    #ifdef _PARALLAXMAP
        //聲明一個(gè)由切線空間的基組成的3x3矩陣“rotation”
        TANGENT_SPACE_ROTATION;
        //計(jì)算視差的視角方向
        half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex));
        //分別將三個(gè)分量賦值給VertexOutputForwardBase結(jié)構(gòu)體對(duì)象o的tangentToWorldAndParallax的三個(gè)分量
        o.tangentToWorldAndParallax[0].w = viewDirForParallax.x;
        o.tangentToWorldAndParallax[1].w = viewDirForParallax.y;
        o.tangentToWorldAndParallax[2].w = viewDirForParallax.z;
    #endif

    //【12】若定義了UNITY_OPTIMIZE_TEXCUBELOD,便計(jì)算反射光方向向量并賦值
    #if UNITY_OPTIMIZE_TEXCUBELOD
        //使用CG語(yǔ)言內(nèi)置函數(shù)reflect計(jì)算反射光方向向量
        o.reflUVW       = reflect(o.eyeVec, normalWorld);
    #endif

    //【13】從頂點(diǎn)中輸出霧數(shù)據(jù)
    UNITY_TRANSFER_FOG(o,o.pos);

    //【14】返回已經(jīng)附好值的VertexOutputForwardBase類型的對(duì)象
    return o;
}

5.2 頂點(diǎn)輸入結(jié)構(gòu)體VertexInput
此結(jié)構(gòu)體定義于UnityStandardInput.cginc頭文件中,是頂點(diǎn)著色函數(shù)vertForwardBase的輸入?yún)?shù)

源碼如下:

//頂點(diǎn)輸入結(jié)構(gòu)體
struct VertexInput
{
    float4 vertex   : POSITION;//位置坐標(biāo)
    half3 normal    : NORMAL;//法線向量
    float2 uv0      : TEXCOORD0;//一級(jí)紋理坐標(biāo)
    float2 uv1      : TEXCOORD1;//二級(jí)紋理坐標(biāo)
    //若DYNAMICLIGHTMAP_ON或者UNITY_PASS_META選項(xiàng)為開,則還定義一個(gè)三級(jí)紋理
#if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META)
    float2 uv2      : TEXCOORD2;//三級(jí)紋理
#endif
#ifdef _TANGENT_TO_WORLD
    half4 tangent   : TANGENT;//切線向量
#endif
};

5.3頂點(diǎn)輸出結(jié)構(gòu)體VertexOutputForwardBase、
VertexOutputForwardBase結(jié)構(gòu)體就是正向基礎(chǔ)渲染通道特有的輸出結(jié)構(gòu)體,定義于UnityStandardCore.cginc頭文件中

源碼如下:

//正向渲染基礎(chǔ)通道的輸出結(jié)構(gòu)體
struct VertexOutputForwardBase
{
    float4 pos                          : SV_POSITION;//像素坐標(biāo)
    float4 tex                          : TEXCOORD0;//一級(jí)紋理
    half3 eyeVec                        : TEXCOORD1;//二級(jí)紋理(視線向量)
    half4 tangentToWorldAndParallax[3]  : TEXCOORD2;    //3x3為切線到世界矩陣的值,1x3為視差方向的值
    half4 ambientOrLightmapUV           : TEXCOORD5;    // 球諧函數(shù)(Spherical harmonics)或光照貼圖的UV坐標(biāo)
    SHADOW_COORDS(6)//陰影坐標(biāo)
    UNITY_FOG_COORDS(7)//霧效坐標(biāo)

    //若定義了鏡面立方體投影宏,定義一個(gè)posWorld
    #if UNITY_SPECCUBE_BOX_PROJECTION
        float3 posWorld                 : TEXCOORD8;
    #endif
    //若定義了優(yōu)化紋理的立方體LOD宏,還將定義如下的參數(shù)reflUVW
    #if UNITY_OPTIMIZE_TEXCUBELOD
        #if UNITY_SPECCUBE_BOX_PROJECTION
            half3 reflUVW               : TEXCOORD9;
        #else
            half3 reflUVW               : TEXCOORD8;
        #endif
    #endif
};

5.4 UNITY_INITIALIZE_OUTPUT宏
UNITY_INITIALIZE_OUTPUT(type,name) –此宏用于將給定類型的名稱變量初始化為零。

5.5 _Object2World矩陣
_Object2World,Unity的內(nèi)置矩陣,世界坐標(biāo)系到對(duì)象坐標(biāo)系的變換矩陣,簡(jiǎn)稱“世界-對(duì)象矩陣”。

5.6 UNITY_MATRIX_MVP矩陣
UNITY_MATRIX_MVP為當(dāng)前的模型矩陣x視圖矩陣x投影矩陣,簡(jiǎn)稱“模型-視圖-投影矩陣”。其常用于在頂點(diǎn)著色函數(shù)中,通過將它和頂點(diǎn)位置相乘,從而可以把頂點(diǎn)位置從模型空間轉(zhuǎn)換到裁剪空間(clip space)中。也就是通過此矩陣,將三維空間中的坐標(biāo)投影到了二維窗口中。

5.7 TexCoords函數(shù)
TexCoords函數(shù)用于獲取紋理坐標(biāo),定義UnityStandardInput.cginc頭文件中,
源碼如下:

float4 TexCoords(VertexInput v)
{
    float4 texcoord;
    texcoord.xy = TRANSFORM_TEX(v.uv0, _MainTex); // Always source from uv0
    texcoord.zw = TRANSFORM_TEX(((_UVSec == 0) ? v.uv0 : v.uv1), _DetailAlbedoMap);
    return texcoord;
}

函數(shù)實(shí)現(xiàn)代碼中的_MainTex、_UVSec、_DetailAlbedoMap都是此頭文件定義的全局的變量。
其中還涉及到了一個(gè)TRANSFORM_TEX宏,在這邊也提一下,它定義于UnityCG.cginc頭文件中,
源碼如下:

// 按比例和偏移進(jìn)行二維UV坐標(biāo)的變換
#define TRANSFORM_TEX(tex,name) (tex.xy *name##_ST.xy + name##_ST.zw)

5.8 NormalizePerVertexNormal函數(shù)
此函數(shù)位于unitystandardcore.cginc頭文件中
源碼如下:

//--------------------------【函數(shù)NormalizePerVertexNormal】-------------------------
// 用途:歸一化每頂點(diǎn)法線
// 說明:若滿足特定條件,便歸一化每頂點(diǎn)法線并返回,否則,直接返回原始值
// 輸入:half3類型的法線坐標(biāo)
// 輸出:若滿足判斷條件,返回half3類型的、經(jīng)過歸一化后的法線坐標(biāo),否則返回輸入的值
//-----------------------------------------------------------------------------------------------
half3 NormalizePerVertexNormal (half3 n)
{
    //滿足著色目標(biāo)模型的版本小于Shader Model 3.0,或者定義了UNITY_STANDARD_SIMPLE宏,返回歸一化后的值
    #if (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
        return normalize(n);
    //否則,直接返回輸入的參數(shù),后續(xù)應(yīng)該會(huì)進(jìn)行逐像素的歸一化
    #else
        return n;
    #endif
}

其中,SHADER_TARGET宏代表的值為和著色器的目標(biāo)編譯模型(shader model)相關(guān)的一個(gè)數(shù)值。

5.9 UnityObjectToWorldNormal函數(shù)
UnityObjectToWorldNormal是Unity內(nèi)置的函數(shù),可以將法線從模型空間變換到世界空間中,定義于UnityCG.cginc頭文件中
源碼如下:

//將法線從模型空間變換到世界空間
inline float3 UnityObjectToWorldNormal( in float3 norm )
{
    // 將分量分別相乘,并進(jìn)行歸一化
    //Multiply by transposed inverse matrix, actually using transpose() generates badly optimized code
    return normalize(_World2Object[0].xyz * norm.x + _World2Object[1].xyz * norm.y + _World2Object[2].xyz * norm.z);
}

其中的normalize( )函數(shù)很常見,是來自CG語(yǔ)言中的函數(shù),作用是歸一化向量。

5.10 UnityObejctToWorldDir函數(shù)
UnityObjectToWorldDir函數(shù)用于方向值從物體空間切換到世界空間,定義于UnityCG.cginc頭文件中
源碼如下

//將方向值從物體空間切換到世界空間
inline float3 UnityObjectToWorldDir( in float3 dir )
{
    return normalize(mul((float3x3)_Object2World, dir));
}

5.11 CreateTangentToWorldPerVertex函數(shù)
CreateTangentToWorldPerVertex函數(shù)用于在世界空間中為每個(gè)頂點(diǎn)創(chuàng)建切線,定義于UnityStandardUtils.cginc頭文件中
源碼如下:

half3x3 CreateTangentToWorldPerVertex(half3 normal, half3 tangent, half tangentSign)
{
    //對(duì)于奇數(shù)負(fù)比例變換,我們需要將符號(hào)反向||<span style="font-family: Arial, Helvetica, sans-serif;">For odd-negative scale transforms we need to flip the sign</span>
    half sign = tangentSign * unity_WorldTransformParams.w;
    half3 binormal = cross(normal, tangent) * sign;
    return half3x3(tangent, binormal, normal);
}

其中的unity_WorldTransformParams是UnityShaderVariables.cginc頭文件中定義的一個(gè)uniform float4型的變量,其w分量用于標(biāo)定奇數(shù)負(fù)比例變換(odd-negativescale transforms),通常取值為1.0或者-1.0。

5.12 TRANSFER_SHADOW(a)宏
此宏用于進(jìn)行陰影在各種空間中的轉(zhuǎn)換,定義于AutoLight.cginc中。在不同的情況下,此宏代表的意義并不相同。
1 Screen space shadows(對(duì)于屏幕空間中的陰影)
對(duì)應(yīng)于屏幕空間中的陰影,也就是#if defined (SHADOWS_SCREEN)
源碼如下:

#if defined (SHADOWS_SCREEN)
……
#if defined(UNITY_NO_SCREENSPACE_SHADOWS)
#define TRANSFER_SHADOW(a) a._ShadowCoord = mul( unity_World2Shadow[0], mul( _Object2World, v.vertex ) );

#else // not UNITY_NO_SCREENSPACE_SHADOWS

#define TRANSFER_SHADOW(a) a._ShadowCoord = ComputeScreenPos(a.pos);
……
#endif

將世界-陰影坐標(biāo)乘以世界-模型坐標(biāo)和物體頂點(diǎn)坐標(biāo)的積,也就是先將物體坐標(biāo)轉(zhuǎn)換成世界坐標(biāo),再將世界坐標(biāo)轉(zhuǎn)換成陰影坐標(biāo),并將結(jié)果存放于a._ShadowCoord中。

2.Spor light shadows(對(duì)于聚光燈陰影)

對(duì)于聚光燈的陰影,也就是#if defined (SHADOWS_DEPTH)&& defined (SPOT)

 #if defined (SHADOWS_DEPTH) && defined (SPOT)
#define TRANSFER_SHADOW(a) a._ShadowCoord = mul (unity_World2Shadow[0], mul(_Object2World,v.vertex));
……
#endif

用途就是先將物體坐標(biāo)轉(zhuǎn)換成世界坐標(biāo),再將世界坐標(biāo)轉(zhuǎn)換成陰影坐標(biāo),并將結(jié)果存放于a._ShadowCoord中。

3.Point light shadows(關(guān)于點(diǎn)光源陰影)

#if defined (SHADOWS_CUBE),有如下定義:
#if defined (SHADOWS_CUBE)
    #define TRANSFER_SHADOW(a) a._ShadowCoord = mul(_Object2World, v.vertex).xyz - _LightPositionRange.xyz;
……
#endif

也就是說,這種情況下的TRANSFER_SHADOW(a)宏代表語(yǔ)句a._ShadowCoord = mul(_Object2World, v.vertex).xyz -_LightPositionRange.xyz;
想了解此代碼的含義,先要知道_LightPositionRange變量的含義。
這個(gè)變量是UnityShaderVariables.cginc頭文件中定義的一個(gè)全局變量:

uniform float4 _LightPositionRange;          // xyq= pos, w = 1/range

此參數(shù)的x,y,z分量表示世界空間下光源的坐標(biāo),而w為世界空間下范圍的倒數(shù)。
就是先將物體-世界矩陣乘以物體頂點(diǎn)坐標(biāo),得到物體的世界空間坐標(biāo),然后取坐標(biāo)的xyz分量,與光源的坐標(biāo)相減,并將結(jié)果賦給a._ShadowCoord。

4.Shadow off(關(guān)閉陰影)
對(duì)于關(guān)閉陰影的情況,也就是#if !defined (SHADOWS_SCREEN)&& !defined (SHADOWS_DEPTH) && !defined (SHADOWS_CUBE),有如下定義:

#if !defined (SHADOWS_SCREEN) && !defined (SHADOWS_DEPTH) && !defined (SHADOWS_CUBE)
    #define TRANSFER_SHADOW(a)
……
#endif

這種情況下的TRANSFER_SHADOW(a)宏代表的是空白

5.13 VertexGlForward函數(shù)
定義于UnityStandardCore.cginc頭文件中
源碼如下:

//頂點(diǎn)正向全局光照函數(shù)
inline half4 VertexGIForward(VertexInput v, float3 posWorld, half3 normalWorld)
{
    //【1】定義一個(gè)half4型的ambientOrLightmapUV變量,并將四個(gè)分量都置為0
    half4 ambientOrLightmapUV = 0;

    //【2】對(duì)ambientOrLightmapUV變量的四個(gè)分量賦值
    // 【2-1】若沒有定義LIGHTMAP_OFF(關(guān)閉光照貼圖)宏,也就是此情況下啟用靜態(tài)的光照貼圖,則計(jì)算對(duì)應(yīng)的光照貼圖坐標(biāo)
    //static lightmap
    #ifndef LIGHTMAP_OFF
        ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
        ambientOrLightmapUV.zw = 0;

    //【2-2】若定義了UNITY_SHOULD_SAMPLE_SH宏,則表示對(duì)動(dòng)態(tài)的對(duì)象采樣(不對(duì)靜態(tài)或者動(dòng)態(tài)的光照貼圖采樣)
    // || Sample light probe for Dynamic objects only (no static or dynamic lightmaps)
    #elif UNITY_SHOULD_SAMPLE_SH

        //【2-2-1】若定義了如下的UNITY_SAMPLE_FULL_SH_PER_PIXEL宏(即采樣計(jì)算全部的每像素球面調(diào)和光照),便給ambientOrLightmapUV.rgb賦值為0
        #if UNITY_SAMPLE_FULL_SH_PER_PIXEL
            ambientOrLightmapUV.rgb = 0;

        //【2-2-2】若滿足著色目標(biāo)模型的版本小于Shader Model 3.0,或者定義了UNITY_STANDARD_SIMPLE宏
        //便使用球面調(diào)和函數(shù)ShadeSH9給ambientOrLightmapUV.rgb賦值
        #elif (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
            ambientOrLightmapUV.rgb = ShadeSH9(half4(normalWorld, 1.0));

        //【2-2-3】否則,使用三序球面調(diào)和函數(shù)ShadeSH3Order給ambientOrLightmapUV.rgb賦值
        #else
            //優(yōu)化操作:光源L0、L1逐像素,光源L2逐頂點(diǎn) ||  Optimization: L2 per-vertex, L0..L1 per-pixel
            ambientOrLightmapUV.rgb = ShadeSH3Order(half4(normalWorld, 1.0));
        #endif

        //【2-2-4】 從非重要的點(diǎn)光源中添加近似的照明 || Add approximated illumination from non-important point lights
        //若定義了如下的VERTEXLIGHT_ON宏(即開啟頂點(diǎn)光照),便使用Shade4PointLights函數(shù)給ambientOrLightmapUV.rgb賦值,添加環(huán)境光
        #ifdef VERTEXLIGHT_ON
            //  Shade4PointLights為Unity內(nèi)置的逐頂點(diǎn)光照處理函數(shù),定義于unityCG.cginc頭文件中
            ambientOrLightmapUV.rgb += Shade4PointLights (
                unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
                unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
                unity_4LightAtten0, posWorld, normalWorld);
        #endif
    #endif

    //【2-3】若定義了如下的VERTEXLIGHT_ONDYNAMICLIGHTMAP_ON宏(即開啟動(dòng)態(tài)光照貼圖),則給變量的zw分量賦值
    #ifdef DYNAMICLIGHTMAP_ON
        ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
    #endif
    //【3】返回ambientOrLightmapUV變量的值
    return ambientOrLightmapUV;
}

1.unity_LightmapST變量

unity_LightmapST變量類型為float4型,定義于UnityShaderVariables.cginc頭文件中,存放著光照貼圖操作的參數(shù)的值

float4 unity_LightmapST

2.UNITY_SHOULD_SAMPLE_SH宏
定義于UnityCG.cginc中
源碼如下:

//包含間接漫反射的動(dòng)態(tài)&靜態(tài)光照貼圖,所以忽略掉球面調(diào)和光照 ||  Dynamic & Static lightmaps contain indirect diffuse ligthing, thus ignore SH
#define UNITY_SHOULD_SAMPLE_SH ( defined (LIGHTMAP_OFF) && defined(DYNAMICLIGHTMAP_OFF) )

就是將LIGHTMAP_OFF(關(guān)閉光照貼圖)宏和DYNAMICLIGHTMAP_OFF(關(guān)閉動(dòng)態(tài)光照貼圖)宏的定義進(jìn)行了封裝

3.UNITY_SAMPLE_FULL_SH_PER_PIXEL宏

UNITY_SAMPLE_FULL_SH_PER_PIXEL宏定義于UnityStandardConfig.cginc頭文件中。其實(shí)也就是一個(gè)標(biāo)識(shí)符,用0標(biāo)示UNITY_SAMPLE_FULL_SH_PER_PIXEL宏是否已經(jīng)定義。按字面上理解,啟用此宏表示我們將采樣計(jì)算每像素球面調(diào)和光照,而不是默認(rèn)的逐頂點(diǎn)計(jì)算球面調(diào)和光照并且線性插值到每像素中。
源碼如下:

#ifndef UNITY_SAMPLE_FULL_SH_PER_PIXEL
#define UNITY_SAMPLE_FULL_SH_PER_PIXEL 0
#endif

4.ShadeSH9函數(shù)
ShadeSH9即球面調(diào)和函數(shù),定義于UnityCG.cginc頭文件中
源碼如下:

//球面調(diào)和函數(shù)
//法線需被初始化,w=1.0 || normal should be normalized, w=1.0
half3 ShadeSH9 (half4 normal)
{
    half3 x1, x2, x3;

    //線性+常數(shù)多項(xiàng)式  || Linear + constant polynomial terms
    x1.r = dot(unity_SHAr,normal);
    x1.g = dot(unity_SHAg,normal);
    x1.b = dot(unity_SHAb,normal);

    //二次多項(xiàng)式的四個(gè)參數(shù) || 4 of the quadratic polynomials
    half4 vB = normal.xyzz * normal.yzzx;
    x2.r = dot(unity_SHBr,vB);
    x2.g = dot(unity_SHBg,vB);
    x2.b = dot(unity_SHBb,vB);

    //最終二次多項(xiàng)式 ||  Final quadratic polynomial
    half vC = normal.x*normal.x - normal.y*normal.y;
    x3 = unity_SHC.rgb * vC;
    return x2 + x3 + x1;
}

5.ShadeSH3Order函數(shù)
定義于UnityCG.cginc頭文件中
源碼如下:

//三序球面調(diào)和函數(shù)
//法線需被初始化,w=1.0 ||  normal should be normalized, w=1.0
half3 ShadeSH3Order(half4 normal)
{
    half3 x2, x3;
    //二次多項(xiàng)式的四個(gè)參數(shù) || 4 of the quadratic polynomials
    half4 vB = normal.xyzz * normal.yzzx;
    x2.r = dot(unity_SHBr,vB);
    x2.g = dot(unity_SHBg,vB);
    x2.b = dot(unity_SHBb,vB);

    //最終的二次多項(xiàng)式 || Final quadratic polynomial
    half vC = normal.x*normal.x - normal.y*normal.y;
    x3 = unity_SHC.rgb * vC;

    return x2 + x3;
}

6.Shade4PointLights函數(shù)

Shade4PointLights為逐頂點(diǎn)光照處理函數(shù),定義于unityCG.cginc頭文件中

//在正向基礎(chǔ)渲染通道中使用,根據(jù)4個(gè)不同的點(diǎn)光源計(jì)算出漫反射光照參數(shù)的rgb值|| Used in ForwardBase pass: Calculates diffuse lighting from 4 point lights, with data packed in a special way.
float3 Shade4PointLights (
    float4 lightPosX, float4 lightPosY, float4 lightPosZ,
    float3 lightColor0, float3 lightColor1, float3 lightColor2, float3 lightColor3,
    float4 lightAttenSq,
    float3 pos, float3 normal)
{
    // 【1】將輸入?yún)?shù)轉(zhuǎn)換為光照矢量 || to light vectors
    float4 toLightX = lightPosX - pos.x;
    float4 toLightY = lightPosY - pos.y;
    float4 toLightZ = lightPosZ - pos.z;
    // 【2】計(jì)算平方的值 || squared lengths
    float4 lengthSq = 0;
    lengthSq += toLightX * toLightX;
    lengthSq += toLightY * toLightY;
    lengthSq += toLightZ * toLightZ;
    // 【3】法線方向點(diǎn)乘光線方向|| NdotL
    float4 ndotl = 0;
    ndotl += toLightX * normal.x;
    ndotl += toLightY * normal.y;
    ndotl += toLightZ * normal.z;
    // 【4】修正NdotL(法線方向點(diǎn)乘光線方向)的值 || correct NdotL
    float4 corr = rsqrt(lengthSq);
    ndotl = max (float4(0,0,0,0), ndotl * corr);
    // 【5】計(jì)算衰減系數(shù) || attenuation
    float4 atten = 1.0 / (1.0 + lengthSq * lightAttenSq);
    float4 diff = ndotl * atten;
    // 【6】得到最終的顏色 || final color
    float3 col = 0;
    col += lightColor0 * diff.x;
    col += lightColor1 * diff.y;
    col += lightColor2 * diff.z;
    col += lightColor3 * diff.w;
    return col;
}

5.14 TANGENT_SPACE_ROTATION宏
TANGENT_SPACE_ROTATION宏定義于UnityCG.cginc中,作用是聲明一個(gè)由切線空間的基組成的3x3矩陣
源碼如下:

//聲明一個(gè)由切線空間的基組成的3x3矩陣 || Declares 3x3 matrix 'rotation', filled with tangent space basis
#define TANGENT_SPACE_ROTATION \
    float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \
    float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal )

使用TANGENT_SPACE_ROTATION宏也就表示定義了上述代碼所示的float3 類型的binormal和float3x3類型的rotation兩個(gè)變量。且其中的rotation為3x3的矩陣,由切線空間的基組成。可以使用它把物體空間轉(zhuǎn)換到切線空間中。

5.15 UNITY_OPTIMIZE_TEXCUBELOD宏

用0標(biāo)識(shí)是否開啟此功能
源碼如下:

#ifndef UNITY_OPTIMIZE_TEXCUBELOD
    #define UNITY_OPTIMIZE_TEXCUBELOD 0
#endif

5.16 reflect函數(shù)

reflect函數(shù)是CG語(yǔ)言的內(nèi)置函數(shù)。
reflect(I, N) 根據(jù)入射光方向向量I,和頂點(diǎn)法向量N,計(jì)算反射光方向向量。其中I 和N必須被歸一化,需要特別注意的是,這個(gè)I 是指向頂點(diǎn)的;且此函數(shù)只對(duì)三元向量有效。

5.17 UNITY_TRANSFER_FOG宏

UNITY_TRANSFER_FOG宏相關(guān)代碼定義于UnityCG.Cginc頭文件中
源碼如下:

//【0】實(shí)現(xiàn)不同版本的UNITY_CALC_FOG_FACTOR宏。
#if defined(FOG_LINEAR)
    // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
    #define UNITY_CALC_FOG_FACTOR(coord) float unityFogFactor = (coord) * unity_FogParams.z + unity_FogParams.w
#elif defined(FOG_EXP)
    // factor = exp(-density*z)
    #define UNITY_CALC_FOG_FACTOR(coord) float unityFogFactor = unity_FogParams.y * (coord); unityFogFactor = exp2(-unityFogFactor)
#elif defined(FOG_EXP2)
    // factor = exp(-(density*z)^2)
    #define UNITY_CALC_FOG_FACTOR(coord) float unityFogFactor = unity_FogParams.x * (coord); unityFogFactor = exp2(-unityFogFactor*unityFogFactor)
#else
    #define UNITY_CALC_FOG_FACTOR(coord) float unityFogFactor = 0.0
#endif

//【1】若已經(jīng)定義了FOG_LINEAR、FOG_EXP、FOG_EXP2宏三者之中至少之一,便可以進(jìn)行到此#if實(shí)現(xiàn)部分
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)

    //【1-1】定義UNITY_FOG_COORDS(idx)宏
    #define UNITY_FOG_COORDS(idx) float fogCoord : TEXCOORD##idx;

    //【1-2】定義UNITY_TRANSFER_FOG(o,outpos)宏
    //【1-2-1】若滿足著色目標(biāo)模型的版本小于Shader Model 3.0,或者定義了SHADER_API_MOBILE宏,便可以進(jìn)行到此#if實(shí)現(xiàn)部分
//UNITY_CALC_FOG_FACTOR宏的實(shí)現(xiàn)見上
    #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)
        // 移動(dòng)平臺(tái)和Shader Model 2.0:計(jì)算每頂點(diǎn)的霧效因子 || mobile or SM2.0: calculate fog factor per-vertex
        #define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord = unityFogFactor
    //【1-2-2】否則
    #else
        // Shader Model 3.0和PC/游戲主機(jī)平臺(tái):計(jì)算每頂點(diǎn)的霧距離,以及每像素霧效因子 || SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel
        #define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord = (outpos).z
    #endif
//【2】否則,直接用UNITY_FOG_COORDS宏計(jì)算霧效參數(shù)
#else
    #define UNITY_FOG_COORDS(idx)
    #define UNITY_TRANSFER_FOG(o,outpos)
#endif

5.18 fragForwardBase(片段著色器函數(shù))

源碼如下:

//----------------------------------------【fragForwardBase函數(shù)】----------------------
//  用途:正向渲染基礎(chǔ)通道的片段著色函數(shù)
//  輸入:VertexOutputForwardBase結(jié)構(gòu)體
//  輸出:一個(gè)half4類型的顏色值
//------------------------------------------------------------------------------------------------------------------
half4 fragForwardBase (VertexOutputForwardBase i) : SV_Target
{
    //定義并初始化類型為FragmentCommonData的變量s
    FRAGMENT_SETUP(s)
    //若定義了UNITY_OPTIMIZE_TEXCUBELOD,則由輸入的頂點(diǎn)參數(shù)來設(shè)置反射光方向向量
#if UNITY_OPTIMIZE_TEXCUBELOD
    s.reflUVW       = i.reflUVW;
#endif

    //設(shè)置主光照
    UnityLight mainLight = MainLight (s.normalWorld);

    //設(shè)置陰影的衰減系數(shù)
    half atten = SHADOW_ATTENUATION(i);

    //計(jì)算全局光照
    half occlusion = Occlusion(i.tex.xy);
    UnityGI gi = FragmentGI (s, occlusion, i.ambientOrLightmapUV, atten, mainLight);

    //加上BRDF-基于物理的光照
    half4 c = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect);
    //加上BRDF-全局光照
    c.rgb += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi);
    //加上自發(fā)光
    c.rgb += Emission(i.tex.xy);

    //設(shè)置霧效
    UNITY_APPLY_FOG(i.fogCoord, c.rgb);

    //返回最終的顏色
    return OutputForward (c, s.alpha);
}

1.FRAGMENT_SETUP(x) 宏
FRAGMENT_SETUP(x)宏定義于UnityStandardCore.cginc頭文件中,其作用其實(shí)就是用FragmentSetup函數(shù)初始化括號(hào)中的x變量。

#define FRAGMENT_SETUP(x) FragmentCommonData x = \
    FragmentSetup(i.tex, i.eyeVec, IN_VIEWDIR4PARALLAX(i), i.tangentToWorldAndParallax, IN_WORLDPOS(i));

調(diào)用此宏,也就是表示寫了如下的代碼,定義了一個(gè)x變量:

FragmentCommonData x =FragmentSetup(i.tex, i.eyeVec, IN_VIEWDIR4PARALLAX(i), i.tangentToWorldAndParallax, IN_WORLDPOS(i));

其中FragmentSetup函數(shù)也定義于UnityStandardCore.cginc頭文件中,用于填充一個(gè)FragmentCommonData結(jié)構(gòu)體并于返回值中返回,也就是進(jìn)行片段函數(shù)相關(guān)參數(shù)的初始化
源碼如下:

//函數(shù)FragmentSetup:填充一個(gè)FragmentCommonData結(jié)構(gòu)體并于返回值中返回,進(jìn)行片段函數(shù)相關(guān)參數(shù)的初始化
inline FragmentCommonData FragmentSetup (float4 i_tex, half3 i_eyeVec, half3 i_viewDirForParallax, half4 tangentToWorld[3], half3 i_posWorld)
{
    i_tex = Parallax(i_tex, i_viewDirForParallax);

    half alpha = Alpha(i_tex.xy);
    #if defined(_ALPHATEST_ON)
        clip (alpha - _Cutoff);
    #endif

    FragmentCommonData o = UNITY_SETUP_BRDF_INPUT (i_tex);
    o.normalWorld = PerPixelWorldNormal(i_tex, tangentToWorld);
    o.eyeVec = NormalizePerPixelNormal(i_eyeVec);
    o.posWorld = i_posWorld;

    // NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
    o.diffColor = PreMultiplyAlpha (o.diffColor, alpha, o.oneMinusReflectivity, /*out*/ o.alpha);
    return o;
}

其中的FragmentCommonData結(jié)構(gòu)體也是定義于UnityStandardCore.cginc頭文件中:

//FragmentCommonData結(jié)構(gòu)體:存放片段著色常用變量
struct FragmentCommonData
{
    half3 diffColor, specColor;//漫反射顏色;鏡面反射顏色
    // Note: oneMinusRoughness & oneMinusReflectivity for optimization purposes, mostly for DX9 SM2.0 level.
    // Most of the math is being done on these (1-x) values, and that saves a few precious ALU slots.
    half oneMinusReflectivity, oneMinusRoughness;//1減去反射率;1減去粗糙度
    half3 normalWorld, eyeVec, posWorld;//世界空間中的法線向量坐標(biāo);視角向量坐標(biāo);在世界坐標(biāo)中的位置坐標(biāo)
    half alpha;//透明度

#if UNITY_OPTIMIZE_TEXCUBELOD || UNITY_STANDARD_SIMPLE
    half3 reflUVW;//反射率的UVW
#endif

#if UNITY_STANDARD_SIMPLE
    half3 tangentSpaceNormal;//切線空間中的法線向量
#endif
};

2.MainLight函數(shù)
MainLight函數(shù)定義于UnityStandardCore.cginc頭文件中,用途是實(shí)例化一個(gè)UnityLight結(jié)構(gòu)體對(duì)象,并進(jìn)行相應(yīng)的填充,其返回值作為主光源
源碼如下:

//  用途:該函數(shù)為主光照函數(shù)
//  說明:實(shí)例化一個(gè)UnityLight結(jié)構(gòu)體對(duì)象,并進(jìn)行相應(yīng)的填充
/*
//注:UnityLight結(jié)構(gòu)體定義于UnityLightingCommon.cginc文件中,原型如下:
struct UnityLight
{
half3 color;
half3 dir;
half  ndotl;
};
*/

//------------------------------------【函數(shù)3】MainLight函數(shù)-----------------------------------------
//  用途:該函數(shù)為主光照函數(shù)
//  說明:實(shí)例化一個(gè)UnityLight結(jié)構(gòu)體對(duì)象,并進(jìn)行相應(yīng)的填充
//---------------------------------------------------------------------------------------------------------
UnityLight MainLight (half3 normalWorld)
{
    //【1】實(shí)例化一個(gè)UnityLight的對(duì)象
    UnityLight l;

    //【2】填充UnityLight的各個(gè)參數(shù)
    //若光照貼圖選項(xiàng)為關(guān),使用Unity內(nèi)置變量賦值
    #ifdef LIGHTMAP_OFF
        //獲取光源的顏色
        l.color = _LightColor0.rgb;
        //獲取光源的方向
        l.dir = _WorldSpaceLightPos0.xyz;
        //獲取法線與光源方向的點(diǎn)乘的積
        l.ndotl = LambertTerm (normalWorld, l.dir);

    //光照貼圖選項(xiàng)為開,將各項(xiàng)值設(shè)為0
    #else
        l.color = half3(0.f, 0.f, 0.f);
        l.ndotl  = 0.f;
        l.dir = half3(0.f, 0.f, 0.f);
    #endif

    //返回賦值完成的UnityLight結(jié)構(gòu)體對(duì)象
    return l;
}

3.SHADOW_ATTENUATION宏
SHADOW_ATTENUATION宏相關(guān)的代碼位于AutoLight.cginc頭文件中,用于實(shí)現(xiàn)陰影渲染相關(guān)的輔助工作
源碼如下:

// ----------------
//  陰影相關(guān)工具代碼 || Shadow helpers
// ----------------

// ---- 屏幕空間陰影 || Screen space shadows
#if defined (SHADOWS_SCREEN)
……
#define SHADOW_ATTENUATION(a) unitySampleShadow(a._ShadowCoord)
#endif

// ----聚光燈光源陰影 || Spot light shadows
#if defined (SHADOWS_DEPTH) && defined (SPOT)
    #define SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
    #define TRANSFER_SHADOW(a) a._ShadowCoord = mul (unity_World2Shadow[0], mul(_Object2World,v.vertex));
    #define SHADOW_ATTENUATION(a) UnitySampleShadowmap(a._ShadowCoord)
#endif

// ----點(diǎn)光源陰影 ||  Point light shadows
#if defined (SHADOWS_CUBE)
    #define SHADOW_COORDS(idx1) unityShadowCoord3 _ShadowCoord : TEXCOORD##idx1;
    #define TRANSFER_SHADOW(a) a._ShadowCoord = mul(_Object2World, v.vertex).xyz - _LightPositionRange.xyz;
    #define SHADOW_ATTENUATION(a) UnitySampleShadowmap(a._ShadowCoord)
#endif

// ---- 關(guān)閉陰影 || Shadows off
#if !defined (SHADOWS_SCREEN) && !defined (SHADOWS_DEPTH) && !defined (SHADOWS_CUBE)
    #define SHADOW_COORDS(idx1)
    #define TRANSFER_SHADOW(a)
    #define SHADOW_ATTENUATION(a) 1.0
#endif

SHADOW_ATTENUATION(a)宏除了在關(guān)閉陰影的狀態(tài)是等于1以外,其他幾種情況都是等價(jià)于UnitySampleShadowmap(a._ShadowCoord)函數(shù)的調(diào)用。而這里的UnitySampleShadowmap函數(shù),定于于UnityShadowLibrary.cginc函數(shù)中
源碼如下:

//------------------------------【UnitySampleShadowmap函數(shù)】-----------------------
// 用途:采樣陰影貼圖,得到陰影衰減值
// 輸入?yún)?shù): float3型的陰影向量坐標(biāo)vec
// 返回值:陰影衰減值
//-------------------------------------------------------------------------------------------------------
inline half UnitySampleShadowmap (float3 vec)
{
    float mydist = length(vec) * _LightPositionRange.w;
    mydist *= 0.97; // bias

    #if defined (SHADOWS_SOFT)
        float z = 1.0/128.0;
        float4 shadowVals;
        shadowVals.x = SampleCubeDistance (vec+float3( z, z, z));
        shadowVals.y = SampleCubeDistance (vec+float3(-z,-z, z));
        shadowVals.z = SampleCubeDistance (vec+float3(-z, z,-z));
        shadowVals.w = SampleCubeDistance (vec+float3( z,-z,-z));
        half4 shadows = (shadowVals < mydist.xxxx) ? _LightShadowData.rrrr : 1.0f;
        return dot(shadows,0.25);
    #else
        float dist = SampleCubeDistance (vec);
        return dist < mydist ? _LightShadowData.r : 1.0;
    #endif
}

4.Occlusion函數(shù)
Occlusion函數(shù)用于進(jìn)行全局光照的第一步。其輸入?yún)?shù)為一個(gè)float2型的紋理坐標(biāo),而其half型的返回值將作為FragmentGI函數(shù)的一個(gè)輸入?yún)?shù)。
源碼如下:

half Occlusion(float2 uv)
{
#if (SHADER_TARGET < 30)
    // SM20: instruction count limitation
    // SM20: simpler occlusion
    return tex2D(_OcclusionMap, uv).g;
#else
    half occ = tex2D(_OcclusionMap, uv).g;
    return LerpOneTo (occ, _OcclusionStrength);
#endif
}

其中的LerpOneTo函數(shù)很簡(jiǎn)單,用于線性插值,輸入兩個(gè)值b和t,返回1+(b-1)*t,具體定義如下:

half LerpOneTo(half b, half t)
{
    half oneMinusT = 1 - t;
    return oneMinusT + b * t;
}

5.UnityGl結(jié)構(gòu)體
UnityGI結(jié)構(gòu)體是Unity中存放全局光照光源信息的結(jié)構(gòu)體,定義于UnityLightingCommon.cginc頭文件中
源碼如下:

//全局光照結(jié)構(gòu)體
struct UnityGI
{
    UnityLight light;//定義第一個(gè)光源參數(shù)結(jié)構(gòu)體,表示第一個(gè)光源
    //若定義了DIRLIGHTMAP_SEPARATE(單獨(dú)的方向光源光照貼圖)
    #ifdef DIRLIGHTMAP_SEPARATE
        //若定義了LIGHTMAP_ON(打開光照貼圖)
        #ifdef LIGHTMAP_ON
            UnityLight light2;//定義第二個(gè)光源參數(shù)結(jié)構(gòu)體,表示第二個(gè)光源
        #endif
        //若定義了DYNAMICLIGHTMAP_ON(打開動(dòng)態(tài)光照貼圖)
        #ifdef DYNAMICLIGHTMAP_ON
            UnityLight light3;//定義第三個(gè)光源參數(shù)結(jié)構(gòu)體,表示第三個(gè)光源
        #endif
    #endif
    UnityIndirect indirect;//Unity中間接光源參數(shù)的結(jié)構(gòu)體
};

其中包含了UnityLight結(jié)構(gòu)體和UnityIndirect結(jié)構(gòu)體,其中UnityLight結(jié)構(gòu)體是Unity Shader中最基本的光照結(jié)構(gòu)體,而UnityIndirect是Unity中存放間接光源信息的結(jié)構(gòu)體。它們兩者也定義于UnityLightingCommon.cginc頭文件中
源碼如下:

//Unity中光源參數(shù)的結(jié)構(gòu)體
struct UnityLight
{
    half3 color;//光源顏色
    half3 dir;//光源方向
    half  ndotl; //入射光方向和當(dāng)前表面法線方向的點(diǎn)積
};

//Unity中間接光源參數(shù)的結(jié)構(gòu)體
struct UnityIndirect
{
    half3 diffuse;//漫反射顏色
    half3 specular;//鏡面反射顏色
};

6.FragmentGl函數(shù)
FragmentGI函數(shù)是片段著色部分全局光照的處理函數(shù),定義于UnityStandardCore.cginc頭文件中
源碼如下:

//函數(shù):片段著色部分全局光照的處理函數(shù)
inline UnityGI FragmentGI (FragmentCommonData s, half occlusion, half4 i_ambientOrLightmapUV, half atten, UnityLight light, bool reflections)
{
    //【1】實(shí)例化一個(gè)UnityGIInput的對(duì)象
    UnityGIInput d;
    //【2】填充此UnityGIInput對(duì)象的各個(gè)值
    d.light = light;
    d.worldPos = s.posWorld;
    d.worldViewDir = -s.eyeVec;
    d.atten = atten;
    #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
        d.ambient = 0;
        d.lightmapUV = i_ambientOrLightmapUV;
    #else
        d.ambient = i_ambientOrLightmapUV.rgb;
        d.lightmapUV = 0;
    #endif
    d.boxMax[0] = unity_SpecCube0_BoxMax;
    d.boxMin[0] = unity_SpecCube0_BoxMin;
    d.probePosition[0] = unity_SpecCube0_ProbePosition;
    d.probeHDR[0] = unity_SpecCube0_HDR;

    d.boxMax[1] = unity_SpecCube1_BoxMax;
    d.boxMin[1] = unity_SpecCube1_BoxMin;
    d.probePosition[1] = unity_SpecCube1_ProbePosition;
    d.probeHDR[1] = unity_SpecCube1_HDR;

    //【3】根據(jù)填充好的UnityGIInput結(jié)構(gòu)體對(duì)象,調(diào)用一下UnityGlobalIllumination函數(shù)
    if(reflections)
    {
        Unity_GlossyEnvironmentData g;
        g.roughness     = 1 - s.oneMinusRoughness;
    #if UNITY_OPTIMIZE_TEXCUBELOD || UNITY_STANDARD_SIMPLE
        g.reflUVW       = s.reflUVW;
    #else
        g.reflUVW       = reflect(s.eyeVec, s.normalWorld);
    #endif

        return UnityGlobalIllumination (d, occlusion, s.normalWorld, g);
    }
    else
    {
        return UnityGlobalIllumination (d, occlusion, s.normalWorld);
    }
}

inline UnityGI FragmentGI (FragmentCommonData s, half occlusion, half4 i_ambientOrLightmapUV, half atten, UnityLight light)
{
    return FragmentGI(s, occlusion, i_ambientOrLightmapUV, atten, light, true);
}

其中的UnityGIInput結(jié)構(gòu)體定義了全局光照所需要的一些函數(shù),定義如下:

//全局光照的輸入?yún)?shù)結(jié)構(gòu)體
struct UnityGIInput
{
    UnityLight light; // 像素光源,由引擎準(zhǔn)備并傳輸過來 || pixel light, sent from the engine

    float3 worldPos;//世界空間中的位置坐標(biāo)
    half3 worldViewDir;//世界空間中的視角方向向量坐標(biāo)
    half atten;//衰減值
    half3 ambient;//環(huán)境光顏色
    half4 lightmapUV; //光照貼圖的UV坐標(biāo),其中 取.xy = static lightmapUV(靜態(tài)光照貼圖的UV) , .zw = dynamic lightmap UV(動(dòng)態(tài)光照貼圖的UV)

    float4 boxMax[2];//box最大值
    float4 boxMin[2];//box最小值
    float4 probePosition[2];//光照探針的位置
    float4 probeHDR[2];//光照探針的高動(dòng)態(tài)范圍圖像(High-Dynamic Range)
};

UnityGIInput 中還包含了UnityLight結(jié)構(gòu)體
FragmentGI函數(shù)最終利用了UnityGlobalIllumination函數(shù),其定義于UnityGlobalIllumination.cginc頭文件中,實(shí)現(xiàn)如下:
inline UnityGI UnityGlobalIllumination (UnityGIInput data, half occlusion, half3 normalWorld)
{
    return UnityGI_Base(data, occlusion, normalWorld);
}

此FragmentGI函數(shù)就是嵌套了一層UnityGI_Base函數(shù)位于UnityGlobalIllumination.cginc頭文件中,源碼如下:
//UnityGI_Base函數(shù):Unity的全局光照Base版
inline UnityGI UnityGI_Base(UnityGIInput data, half occlusion, half3 normalWorld)
{
    //【1】實(shí)例化一個(gè)UnityGI類型的結(jié)構(gòu)體
    UnityGI o_gi;
    //【2】重置此UnityGI的結(jié)構(gòu)體
    ResetUnityGI(o_gi);

    //【3】開始逐個(gè)填充參數(shù)
    #if !defined(LIGHTMAP_ON)
        o_gi.light = data.light;
        o_gi.light.color *= data.atten;
    #endif

    #if UNITY_SHOULD_SAMPLE_SH
        #if UNITY_SAMPLE_FULL_SH_PER_PIXEL
            half3 sh = ShadeSH9(half4(normalWorld, 1.0));
        #elif (SHADER_TARGET >= 30) && !UNITY_STANDARD_SIMPLE
            half3 sh = data.ambient + ShadeSH12Order(half4(normalWorld, 1.0));
        #else
            half3 sh = data.ambient;
        #endif

        o_gi.indirect.diffuse = sh;
    #endif

    #if defined(LIGHTMAP_ON)
        // Baked lightmaps
        fixed4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, data.lightmapUV.xy);
        half3 bakedColor = DecodeLightmap(bakedColorTex);

        #ifdef DIRLIGHTMAP_OFF
            o_gi.indirect.diffuse = bakedColor;

            #ifdef SHADOWS_SCREEN
                o_gi.indirect.diffuse = MixLightmapWithRealtimeAttenuation (o_gi.indirect.diffuse, data.atten, bakedColorTex);
            #endif // SHADOWS_SCREEN

        #elif DIRLIGHTMAP_COMBINED
            fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER (unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
            o_gi.indirect.diffuse = DecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);

            #ifdef SHADOWS_SCREEN
                o_gi.indirect.diffuse = MixLightmapWithRealtimeAttenuation (o_gi.indirect.diffuse, data.atten, bakedColorTex);
            #endif // SHADOWS_SCREEN

        #elif DIRLIGHTMAP_SEPARATE
            // Left halves of both intensity and direction lightmaps store direct light; right halves - indirect.

            // Direct
            fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
            o_gi.indirect.diffuse = DecodeDirectionalSpecularLightmap (bakedColor, bakedDirTex, normalWorld, false, 0, o_gi.light);

            // Indirect
            half2 uvIndirect = data.lightmapUV.xy + half2(0.5, 0);
            bakedColor = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, uvIndirect));
            bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, uvIndirect);
            o_gi.indirect.diffuse += DecodeDirectionalSpecularLightmap (bakedColor, bakedDirTex, normalWorld, false, 0, o_gi.light2);
        #endif
    #endif

    #ifdef DYNAMICLIGHTMAP_ON
        // Dynamic lightmaps
        fixed4 realtimeColorTex = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, data.lightmapUV.zw);
        half3 realtimeColor = DecodeRealtimeLightmap (realtimeColorTex);

        #ifdef DIRLIGHTMAP_OFF
            o_gi.indirect.diffuse += realtimeColor;

        #elif DIRLIGHTMAP_COMBINED
            half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);
            o_gi.indirect.diffuse += DecodeDirectionalLightmap (realtimeColor, realtimeDirTex, normalWorld);

        #elif DIRLIGHTMAP_SEPARATE
            half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);
            half4 realtimeNormalTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicNormal, unity_DynamicLightmap, data.lightmapUV.zw);
            o_gi.indirect.diffuse += DecodeDirectionalSpecularLightmap (realtimeColor, realtimeDirTex, normalWorld, true, realtimeNormalTex, o_gi.light3);
        #endif
    #endif

    o_gi.indirect.diffuse *= occlusion;

    //【4】返回此UnityGI類型的結(jié)構(gòu)體
    return o_gi;
}

7.UNITY_BRDF_PBS宏
定義于UnityPBSLighting.cginc頭文件中,根據(jù)不同的情況,將UNITY_BRDF_PBS宏定義為不同版本的UNITY_BRDF_PBS宏——是BRDF3_Unity_PBS、BRDF2_Unity_PBS還是BRDF1_Unity_PBS。
源碼如下:

//-------------------------------------------------------------------------------------
// 默認(rèn)使用BRDF || Default BRDF to use:
#if !defined (UNITY_BRDF_PBS) // 允許顯式地在自定義著色器中重寫B(tài)RDF的實(shí)現(xiàn)細(xì)節(jié) || allow to explicitly override BRDF in custom shader
    //滿足著色目標(biāo)模型的版本小于Shader Model 3.0,或者是PlayStation 2平臺(tái)
    #if (SHADER_TARGET < 30) || defined(SHADER_API_PSP2)
        // 為小于SM3.0的著色模型回退為低保真度的BRDF版本 || Fallback to low fidelity one for pre-SM3.0
        #define UNITY_BRDF_PBS BRDF3_Unity_PBS
    #elif defined(SHADER_API_MOBILE)
        // 為移動(dòng)平臺(tái)簡(jiǎn)化的BRDF版本 || Somewhat simplified for mobile
        #define UNITY_BRDF_PBS BRDF2_Unity_PBS
    #else
        //最高特效的SM3、PC平臺(tái)或者游戲主機(jī)平臺(tái)的BRDF版本 || Full quality for SM3+ PC / consoles
        #define UNITY_BRDF_PBS BRDF1_Unity_PBS
    #endif
#endif

三種情況下,BRDF3_Unity_PBS、BRDF2_Unity_PBS、 BRDF1_Unity_PBS三個(gè)函數(shù)的參數(shù)和返回值都一樣,區(qū)別是內(nèi)部的實(shí)現(xiàn)。在這邊,以BRDF1_Unity_PBS為例。

half4 BRDF1_Unity_PBS (half3 diffColor,half3 specColor, half oneMinusReflectivity, half oneMinusRoughness,half3 normal,half3 viewDir,UnityLight light, UnityIndirect gi)

第一個(gè)參數(shù),half3型的diffColor,表示漫反射顏色的值。
第二個(gè)參數(shù),half3型的specColor,表示鏡面反射顏色值。
第三個(gè)參數(shù),half型的oneMinusReflectivity,表示1減去反射率的值。
第四個(gè)參數(shù),half型的oneMinusRoughness,表示1減去粗糙度的值。
第五次參數(shù),half3型的normal,表示法線的方向。
第六個(gè)參數(shù),half3型的viewDir,表示視線的方向。
第七個(gè)參數(shù),UnityLight型的light,表示Unity中光源參數(shù)的結(jié)構(gòu)體,包含half3型的光源顏色color,half3型的光源方向dir,half型的入射光方向和當(dāng)前表面法線方向的點(diǎn)乘的積ndotl。

struct UnityLight
{
    half3 color;//光源顏色
    half3 dir;//光源方向
    half  ndotl; //入射光方向和當(dāng)前表面法線方向的點(diǎn)積
};

第八個(gè)參數(shù),UnityIndirect類型的gi ,一個(gè)包含了half3型的漫反射顏色diffuse和half3型的鏡面反射顏色specular的光線反射結(jié)構(gòu)體,表示間接光照信息。

struct UnityIndirect
{
    half3 diffuse;//漫反射顏色
    half3 specular;//鏡面反射顏色
};

三種版本的函數(shù)分別貼出來,它們都定義于UnityStandardBRDF.cginc頭文件中。
(1)BRDF1_Unity_PBS

//最高特效的SM3、PC平臺(tái)或者游戲主機(jī)平臺(tái)的BRDF版本 || Full quality for SM3+ PC / consoles
//-------------------------------------------------------------------------------------

// Note: BRDF entry points use oneMinusRoughness (aka "smoothness") and oneMinusReflectivity for optimization
// purposes, mostly for DX9 SM2.0 level. Most of the math is being done on these (1-x) values, and that saves
// a few precious ALU slots.

// Main Physically Based BRDF
// Derived from Disney work and based on Torrance-Sparrow micro-facet model
//
//   BRDF = kD / pi + kS * (D * V * F) / 4
//   I = BRDF * NdotL
//
// * NDF (depending on UNITY_BRDF_GGX):
//  a) Normalized BlinnPhong
//  b) GGX
// * Smith for Visiblity term
// * Schlick approximation for Fresnel
half4 BRDF1_Unity_PBS (half3 diffColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness,
    half3 normal, half3 viewDir,
    UnityLight light, UnityIndirect gi)
{
    half roughness = 1-oneMinusRoughness;
    half3 halfDir = Unity_SafeNormalize (light.dir + viewDir);

    half nl = light.ndotl;
    half nh = BlinnTerm (normal, halfDir);
    half nv = DotClamped (normal, viewDir);
    half lv = DotClamped (light.dir, viewDir);
    half lh = DotClamped (light.dir, halfDir);

#if UNITY_BRDF_GGX
    half V = SmithGGXVisibilityTerm (nl, nv, roughness);
    half D = GGXTerm (nh, roughness);
#else
    half V = SmithBeckmannVisibilityTerm (nl, nv, roughness);
    half D = NDFBlinnPhongNormalizedTerm (nh, RoughnessToSpecPower (roughness));
#endif

    half nlPow5 = Pow5 (1-nl);
    half nvPow5 = Pow5 (1-nv);
    half Fd90 = 0.5 + 2 * lh * lh * roughness;
    half disneyDiffuse = (1 + (Fd90-1) * nlPow5) * (1 + (Fd90-1) * nvPow5);

    // HACK: theoretically we should divide by Pi diffuseTerm and not multiply specularTerm!
    // BUT 1) that will make shader look significantly darker than Legacy ones
    // and 2) on engine side "Non-important" lights have to be divided by Pi to in cases when they are injected into ambient SH
    // NOTE: multiplication by Pi is part of single constant together with 1/4 now

    half specularTerm = max(0, (V * D * nl) * unity_LightGammaCorrectionConsts_PIDiv4);// Torrance-Sparrow model, Fresnel is applied later (for optimization reasons)
    half diffuseTerm = disneyDiffuse * nl;

    half grazingTerm = saturate(oneMinusRoughness + (1-oneMinusReflectivity));
    half3 color =   diffColor * (gi.diffuse + light.color * diffuseTerm)
                    + specularTerm * light.color * FresnelTerm (specColor, lh)
                    + gi.specular * FresnelLerp (specColor, grazingTerm, nv);

    return half4(color, 1);
}

(2)BRDF2_Unity_PBS

// 為移動(dòng)平臺(tái)簡(jiǎn)化的BRDF版本 || Somewhat simplified for mobile
// Based on Minimalist CookTorrance BRDF
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
//
// * BlinnPhong as NDF
// * Modified Kelemen and Szirmay-Kalos for Visibility term
// * Fresnel approximated with 1/LdotH
half4 BRDF2_Unity_PBS (half3 diffColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness,
    half3 normal, half3 viewDir,
    UnityLight light, UnityIndirect gi)
{
    half3 halfDir = Unity_SafeNormalize (light.dir + viewDir);

    half nl = light.ndotl;
    half nh = BlinnTerm (normal, halfDir);
    half nv = DotClamped (normal, viewDir);
    half lh = DotClamped (light.dir, halfDir);

    half roughness = 1-oneMinusRoughness;
    half specularPower = RoughnessToSpecPower (roughness);
    // Modified with approximate Visibility function that takes roughness into account
    // Original ((n+1)*N.H^n) / (8*Pi * L.H^3) didn't take into account roughness
    // and produced extremely bright specular at grazing angles

    // HACK: theoretically we should divide by Pi diffuseTerm and not multiply specularTerm!
    // BUT 1) that will make shader look significantly darker than Legacy ones
    // and 2) on engine side "Non-important" lights have to be divided by Pi to in cases when they are injected into ambient SH
    // NOTE: multiplication by Pi is cancelled with Pi in denominator

    half invV = lh * lh * oneMinusRoughness + roughness * roughness; // approx ModifiedKelemenVisibilityTerm(lh, 1-oneMinusRoughness);
    half invF = lh;
    half specular = ((specularPower + 1) * pow (nh, specularPower)) / (unity_LightGammaCorrectionConsts_8 * invV * invF + 1e-4h); // @TODO: might still need saturate(nl*specular) on Adreno/Mali

    // Prevent FP16 overflow on mobiles
#if SHADER_API_GLES || SHADER_API_GLES3
    specular = clamp(specular, 0.0, 100.0);
#endif

    half grazingTerm = saturate(oneMinusRoughness + (1-oneMinusReflectivity));
    half3 color =   (diffColor + specular * specColor) * light.color * nl
                    + gi.diffuse * diffColor
                    + gi.specular * FresnelLerpFast (specColor, grazingTerm, nv);

    return half4(color, 1);
}

(3)BRDF3_Unity_PBS

// 為小于SM3.0的著色模型回退為低保真度的BRDF版本 || Fallback to low fidelity one for pre-SM3.0
// Old school, not microfacet based Modified Normalized Blinn-Phong BRDF
// Implementation uses Lookup texture for performance
//
// * Normalized BlinnPhong in RDF form
// * Implicit Visibility term
// * No Fresnel term
//
// TODO: specular is too weak in Linear rendering mode
half4 BRDF3_Unity_PBS (half3 diffColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness,
    half3 normal, half3 viewDir,
    UnityLight light, UnityIndirect gi)
{
    half3 reflDir = reflect (viewDir, normal);

    half nl = light.ndotl;
    half nv = DotClamped (normal, viewDir);

    // Vectorize Pow4 to save instructions
    half2 rlPow4AndFresnelTerm = Pow4 (half2(dot(reflDir, light.dir), 1-nv));  // use R.L instead of N.H to save couple of instructions
    half rlPow4 = rlPow4AndFresnelTerm.x; // power exponent must match kHorizontalWarpExp in NHxRoughness() function in GeneratedTextures.cpp
    half fresnelTerm = rlPow4AndFresnelTerm.y;

    half grazingTerm = saturate(oneMinusRoughness + (1-oneMinusReflectivity));

    half3 color = BRDF3_Direct(diffColor, specColor, rlPow4, oneMinusRoughness);
    color *= light.color * nl;
    color += BRDF3_Indirect(diffColor, specColor, gi, grazingTerm, fresnelTerm);

    return half4(color, 1);
}

ps:BRDF1_Unity_PBS函數(shù)的實(shí)現(xiàn)部分用到了最多的變量,最終表現(xiàn)效果最好,主要用于Shader Model 3.0、PC平臺(tái)或者游戲主機(jī)平臺(tái)。BRDF2_Unity_PBS簡(jiǎn)化了一部分計(jì)算,主要用于移動(dòng)平臺(tái),而BRDF3_Unity_PBS是為Shader Model 小于3.0的著色模型提供基本版的BRDF,實(shí)現(xiàn)細(xì)節(jié)最為簡(jiǎn)陋。

8.UNITY_BRDF_GI宏
UNITY_BRDF_GI宏位于UnityPBSLighting.cginc頭文件中
源碼如下:

//-------------------------------------------------------------------------------------
// 從間接的方向光照貼圖中進(jìn)行BRDF(雙向反射分布函數(shù))的光照提取 || BRDF for lights extracted from *indirect* directional lightmaps (baked and realtime).
// 使用UNITY_BRDF_PBS從方向光源烘焙方向光照貼圖, || Baked directional lightmap with *direct* light uses UNITY_BRDF_PBS.
// 若想得到更好的效果,可以使用BRDF1_Unity_PBS || For better quality change to BRDF1_Unity_PBS.
// SM2.0中的非方向光照貼圖|| No directional lightmaps in SM2.0.

//若沒有定義UNITY_BRDF_PBS_LIGHTMAP_INDIRECT宏
#if !defined(UNITY_BRDF_PBS_LIGHTMAP_INDIRECT)
    //定義UNITY_BRDF_PBS_LIGHTMAP_INDIRECT = BRDF2_Unity_PBS
    #define UNITY_BRDF_PBS_LIGHTMAP_INDIRECT BRDF2_Unity_PBS
#endif
//若沒有定義UNITY_BRDF_GI宏
#if !defined (UNITY_BRDF_GI)
    //定義UNITY_BRDF_GI = BRDF_Unity_Indirect
    #define UNITY_BRDF_GI BRDF_Unity_Indirect
#endif

上面這段代碼中關(guān)于UNITY_BRDF_GI宏的地方,就是說若沒有定義UNITY_BRDF_GI宏,就定義一個(gè)UNITY_BRDF_GI宏等價(jià)于BRDF_Unity_Indirect。這邊的BRDF_Unity_Indirect是一個(gè)函數(shù)名,就緊緊跟在上面這段宏代碼的后面:

//間接光照的BRDF
inline half3 BRDF_Unity_Indirect (half3 baseColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness, half3 normal, half3 viewDir, half occlusion, UnityGI gi)
{
    half3 c = 0;
    #if defined(DIRLIGHTMAP_SEPARATE)
        gi.indirect.diffuse = 0;
        gi.indirect.specular = 0;

        #ifdef LIGHTMAP_ON
            c += UNITY_BRDF_PBS_LIGHTMAP_INDIRECT (baseColor, specColor, oneMinusReflectivity, oneMinusRoughness, normal, viewDir, gi.light2, gi.indirect).rgb * occlusion;
        #endif
        #ifdef DYNAMICLIGHTMAP_ON
            c += UNITY_BRDF_PBS_LIGHTMAP_INDIRECT (baseColor, specColor, oneMinusReflectivity, oneMinusRoughness, normal, viewDir, gi.light3, gi.indirect).rgb * occlusion;
        #endif
    #endif
    return c;
}

關(guān)于此段代碼,BRDF_Unity_Indirect 函數(shù)的核心部分其實(shí)就是在調(diào)用UNITY_BRDF_PBS_LIGHTMAP_INDIRECT,而上文的宏有交代過,UNITY_BRDF_PBS_LIGHTMAP_INDIRECT宏等價(jià)于 BRDF2_Unity_PBS。而BRDF2_Unity_PBS函數(shù),其定義于UnityStandardBRDF.cginc中

9.Emission函數(shù)
Emission函數(shù)定于于UnityStandardInput.cginc頭文件中,根據(jù)指定的自發(fā)光光照貼圖,利用tex2D函數(shù),對(duì)輸入的紋理進(jìn)行光照貼圖的采樣
源碼如下:

//---------------------------------------【Emission函數(shù)】--------------------------------
// 用途:根據(jù)指定的自發(fā)光光照貼圖,利用tex2D函數(shù),對(duì)輸入的紋理進(jìn)行光照貼圖的采樣
// 輸入?yún)?shù):float2型的紋理坐標(biāo)
// 輸出參數(shù):經(jīng)過將自發(fā)光紋理和輸入紋理進(jìn)行tex2D采樣得到的half3型的自發(fā)光顏色
//-----------------------------------------------------------------------------------------------
half3 Emission(float2 uv)
{
#ifndef _EMISSION
    return 0;
#else
    return tex2D(_EmissionMap, uv).rgb * _EmissionColor.rgb;
#endif
}

其中用于采樣的自發(fā)光貼圖對(duì)應(yīng)的函數(shù)定義于UnityStandardInput.cginc頭文件的一開始部分。

sampler2D     _EmissionMap;

相當(dāng)于在CGPROGRAM中的頂點(diǎn)和片段著色函數(shù)之前,對(duì)這個(gè)變量進(jìn)行聲明,以便于CG語(yǔ)言塊中使用的時(shí)候,能識(shí)別到他的含義。因?yàn)樵赟tandard.shader源碼的一開始,Properties塊也就是屬性值聲明部分,對(duì)其進(jìn)行了屬性的聲明:

//自發(fā)光紋理圖
_EmissonMap(“Emisson”,2D) = “white” { }

10.UNITY_APPLY_FOG宏
UNITY_APPLY_FOG宏相關(guān)的一些代碼用于霧效的啟用與否的輔助工作,定義于UnityCG.cginc頭文件中
源碼如下:

//UNITY_FOG_LERP_COLOR宏的定義
#define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.rgb = lerp((fogCol).rgb, (col).rgb, saturate(fogFac))

//【1】若已經(jīng)定義了FOG_LINEAR、FOG_EXP、FOG_EXP2宏三者至少之一,便可以進(jìn)行到此#if實(shí)現(xiàn)部分
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
    //【1-1】若滿足著色目標(biāo)模型的版本小于Shader Model 3.0,或者定義了SHADER_API_MOBILE宏,便可以進(jìn)行到此#if實(shí)現(xiàn)部分
    #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)
        //移動(dòng)平臺(tái)和Shader Model 2.0:已經(jīng)計(jì)算了每頂點(diǎn)的霧效因子,所以插一下值就可以了 ||mobile or SM2.0: fog factor was already calculated per-vertex, so just lerp the color
        //定義 UNITY_APPLY_FOG_COLOR(coord,col,fogCol) 等價(jià)于UNITY_FOG_LERP_COLOR(col,fogCol,coord)
    #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_FOG_LERP_COLOR(col,fogCol,coord)

    //【1-2】 Shader Model 3.0和PC/游戲主機(jī)平臺(tái):計(jì)算霧效因子以及進(jìn)行霧顏色的插值 ||SM3.0 and PC/console: calculate fog factor and lerp fog color
    #else
        //定義 UNITY_APPLY_FOG_COLOR(coord,col,fogCol)等價(jià)于UNITY_CALC_FOG_FACTOR(coord); UNITY_FOG_LERP_COLOR(col,fogCol,unityFogFactor)
        #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_CALC_FOG_FACTOR(coord); UNITY_FOG_LERP_COLOR(col,fogCol,unityFogFactor)
    #endif
//【2】否則,直接定義UNITY_APPLY_FOG_COLOR宏
#else
    #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol)
#endif
//【3】若定義了UNITY_PASS_FORWARDADD(正向附加渲染通道)宏
#ifdef UNITY_PASS_FORWARDADD
    //定義UNITY_APPLY_FOG(coord,col) 等價(jià)于UNITY_APPLY_FOG_COLOR(coord,col,fixed4(0,0,0,0))
    #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,fixed4(0,0,0,0))
//【4】否則,UNITY_APPLY_FOG(coord,col) 等價(jià)于 UNITY_APPLY_FOG_COLOR(coord,col,unity_FogColor)
#else
    #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,unity_FogColor)
#endif

11.OutputForward函數(shù)
OutputForward函數(shù)定義于UnityStandardCore.cginc頭文件中,其為正向渲染通道的輸出函數(shù)
源碼如下:

//-----------------------------【函數(shù)OutputForward】-----------------------------------
// 用途:正向渲染通道輸出函數(shù)
//  輸入?yún)?shù):一個(gè)half4類型的一個(gè)顏色值output,一個(gè)half型的透明度值alphaFromSurface
// 返回值:經(jīng)過透明處理的half4型的輸出顏色值
//-------------------------------------------------------------------------------------------------
half4 OutputForward (half4 output, half alphaFromSurface)
{
    #if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON)
        output.a = alphaFromSurface;
    #else
        UNITY_OPAQUE_ALPHA(output.a);
    #endif
    return output;
}

其中UNITY_OPAQUE_ALPHA宏的定義為:

#define UNITY_OPAQUE_ALPHA(outputAlpha)  outputAlpha = 1.0

六、Bidirectional ReflectanceDistribution Function,BRDF(雙向反射分布函數(shù))
雙向反射分布函數(shù)(Bidirectional ReflectanceDistribution Function,BRDF)用來定義給定入射方向上的輻射照度(irradiance)如何影響給定出射方向上的輻射率(radiance)。更籠統(tǒng)地說,它描述了入射光線經(jīng)過某個(gè)表面反射后如何在各個(gè)出射方向上分布——這可以是從理想鏡面反射到漫反射、各向同性(isotropic)或者各向異性(anisotropic)的各種反射。

參考:

  1. 如何正確理解 BRDF (雙向反射分布函數(shù))? - 計(jì)算機(jī) - 知乎
    2.圖形學(xué)理論知識(shí):BRDF 雙向反射分布函數(shù)
  2. An Introduction to BRDF-based Lighting –Nvidia
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,821評(píng)論 25 708
  • 一、Unity5中的Standard Shader Unity5中重點(diǎn)推出了一套基于物理的著色(Physicall...
    CarlDonitz閱讀 867評(píng)論 0 1
  • 鞭炮聲漸漸弱了,盤腿坐在床上翻看手機(jī)圖庫(kù),可惜過渡手機(jī)并沒有存什么精彩有趣的圖片,算了,不加圖也是可以說話的。 回...
    葉徵調(diào)閱讀 343評(píng)論 1 2
  • 標(biāo)簽(空格分隔): 編程 Go官方文檔 Using the tour 1.1 Hello, 世界 Welcome...
    uangianlap閱讀 1,523評(píng)論 0 5