五、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)的各種反射。
參考:
- 如何正確理解 BRDF (雙向反射分布函數(shù))? - 計(jì)算機(jī) - 知乎
2.圖形學(xué)理論知識(shí):BRDF 雙向反射分布函數(shù) - An Introduction to BRDF-based Lighting –Nvidia