4.1 UnityShaderVariables.cginc文件中的著色器常量和函數
4.1.1 進行變換操作用的矩陣
????????1.判斷USING DIRECTIONAL LIGTH宏是否定義并分析與立體渲染相關的宏
????????立體多例化渲染技術的核心思想是一次向渲染管道上提交兩份待渲染的幾何體數據,減少繪制調用(draw call)的次數,提升渲染性能。
????????單程立體渲染(single pass stereo rendering)相關的預處理宏UNITY_SINGLE_PASS_STEREO、立體多例化渲染(stereo instancing rendering)預處理宏UNITY_STEREO_INSTANCING_ENABLED、多視角立體渲染(multi-view stereo rendering)預處理宏UNITY_STEREO_MULTIVIEW_ENABLED的啟用情況決定宏USING_STEREO_MATRICES是否開啟。
????????如果上面3個宏有任意一個是開啟的,那么宏USING_STEREO_MATRICES即開啟,表示要使用與立體渲染相關的矩陣。
????????2.和立體渲染相關的一系列矩陣1
????????下面的代碼用于定義一系列與立體渲染相關的矩陣。
// 所在文件:UnityShaderVariables.cginc代碼// 所在目錄:CGIncludes// 從原文件第16行開始,至第27行結束// 如果要使用和立體渲染相關的矩陣#if defined(USING_STEREO_MATRICES)#define glstate_matrix_projection unity_StereoMatrixP[unity_StereoEyeIndex]#define unity_MatrixV unity_StereoMatrixV[unity_StereoEyeIndex]#define unity_MatrixInvV unity_StereoMatrixInvV[unity_StereoEyeIndex]#define unity_MatrixVP unity_StereoMatrixVP[unity_StereoEyeIndex]#define unity_CameraProjection unity_StereoCameraProjection[unity_StereoEyeIndex]#define unity_CameraInvProjection \unity_StereoCameraInvProjection[unity_StereoEyeIndex]#define unity_WorldToCamera unity_StereoWorldToCamera[unity_StereoEyeIndex]#define unity_CameraToWorld unity_StereoCameraToWorld[unity_StereoEyeIndex]#define _WorldSpaceCameraPos \unity_StereoWorldSpaceCameraPos[unity_StereoEyeIndex]#endif
????????3.和立體渲染相關的一系列矩陣2
????????帶有unity_Stereo前綴的變量和unity_StereoEyeIndex也定義在UnityShaderVariables.cginc文件中。
????????4.UNITY DECLARE MULTIVIEW宏的定義
????????代碼中的UNITY_DECLARE_MULTIVIEW在HLSLSupport.cginc文件中定義,展開如下。
// 所在文件:HLSLSupport.cginc代碼// 所在目錄:CGIncludes// 從原文件第262行開始,至第262行結束#define UNITY_DECLARE_MULTIVIEW(number_of_views) \GLOBAL_CBUFFER_START(OVR_multiview)\uintgl_ViewID;\uintnumViews_##number_of_views;\GLOBAL_CBUFFER_END
4.1.2 和攝像機相關的常量緩沖區
????????1.常量緩沖區UnityPerCamera的定義
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第45行開始,至第85行結束
// D3D11把所有的shader變量組織進constant buffer中去。大部分U3D內
// 建shader變量也組織進constant buffer中去,用戶自定義的shader變
// 量也可以組織進constant buffer中去。定義一個constant buffer以存儲
// shader變量,如下面的定義方式:
// CBUFFER_START(MyRarelyUpdatedVariables)
// float4 _SomeGlobalValue;
// CBUFFER_END
// Unity 3D內建的,用來傳遞給每個攝像機的參數組
// 這些參數由引擎從C#層代碼傳遞給著色器
CBUFFER_START(UnityPerCamera)
? ? float4_Time; // 從載入當前的scene開始算起流逝的時間值,單位是s。其x、y、z、w分量分別對
? ? ? ? ? ? ? ? ? ? // 應為1/20流逝時間值、流逝時間值、2倍流逝時間值、3倍流逝時間值
? ? float4_SinTime; // _Time值的正弦值,其x、y、z、w分別對應于1/8的當前流逝時間值的正弦值、
? ? ? ? ? ? ? ? ? ? // 1/4的當前流逝時間值的正弦值、1/2的當前流逝時間值的正弦值、當前流逝時間
? ? ? ? ? ? ? ? ? ? // 值的正弦值
? ? float4_CosTime; // _Time值的余弦值,其x、y、z、w分別對應于1/8的當前流逝時間值的余弦值、
? ? ? ? ? ? ? ? ? ? // 1/4的當前流逝時間值的余弦值、1/2的當前流逝時間值的余弦值、當前流逝時間
? ? ? ? ? ? ? ? ? ? // 值的余弦值
? ? float4unity_DeltaTime; // 本幀到上一幀過去的時間間隔
? ? // 如果沒有定義開啟單程立體渲染,沒有開啟立體多例化渲染,就由引擎C#層代碼傳遞一個表征當前攝像機
? ? // 在世界空間中的坐標值
#if !defined(UNITY_SINGLE_PASS_STEREO)
&& !defined(STEREO_INSTANCING_ON)
? ? float3_WorldSpaceCameraPos;
#endif
? ? // 投影矩陣相關的參數,x為1或者-1,y為近截平面值,z為遠截平面值,w為遠
? ? // 截平面值的倒數
? ? float4_ProjectionParams;
? ? // 視口相關的參數,x為視口寬度,y為視口高度,z為1加上視口寬度的倒數,w為1加上視口高度的倒數
? ? float4_ScreenParams;
? ? // 用來線性化Z buffer
? ? // x分量為1減去視截體遠截面值與視錐近截面值的商,y分量為視截體遠截面值與
? ? // 視錐近截面值的商,z分量為x分量除以視截體遠截面值,w分量為y分量除以視截體遠截面值
? ? float4_ZBufferParams;
? ? // x分量為正交投影攝像機的寬度,y分量為正交投影攝像機的高度
? ? // z分量未使用,w分量當攝像機為正交投影時為1,透視投影為0
? ? float4unity_OrthoParams;
CBUFFER_END
????????2. 常量緩沖區UnityPerCameraRare的定義
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第88行開始,至第100行結束
CBUFFER_START(UnityPerCameraRare)
// 當前攝像機視截體(view frustum)的6個截平面的平面表達式。這些平面表達式在世界坐標系下描述。
// 每個平面表達式用方程ax+by+cz+d = 0表達。float4中的分量x、y、z、w依次存儲了系數a、b、c、d。
// 6個平面依次是左、右、下、上、近、遠裁剪平面
? ? float4unity_CameraWorldClipPlanes[6];
//如果不使用立體渲染,各種矩陣變量就是一個單變量而不是兩個變量的數組
#if !defined(USING_STEREO_MATRICES)
? ? // 當前攝像機的投影矩陣
? ? float4x4unity_CameraProjection;
? ? // 當前攝像機的投影矩陣的逆矩陣
? ? float4x4unity_CameraInvProjection;
? ? // 當前攝像機的觀察矩陣
? ? float4x4unity_WorldToCamera;
? ? // 當前攝像機的觀察矩陣的逆矩陣
? ? float4x4unity_CameraToWorld;
#endif
CBUFFER_END
4.1.3 與光照相關的工具函數和內置光源
????????1.變量WorldSpaceLightPos0的定義
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第106行開始,至第112行結束
CBUFFER_START(UnityLighting)
#ifdef USING_DIRECTIONAL_LIGHT // 有向平行光
? ? // 分量x、y、z存儲的是有向平行光的方向向量
? ? half4_WorldSpaceLightPos0;
#else //如果不是有向平行光,那么分量x、y、z存儲的是光源在世界空間中的位置坐標
? ? float4_WorldSpaceLightPos0;
#endif
????????2. 4個非重要點光源的位置、衰減值和照射范圍
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第114行開始,至第123行結束
? ? float4_LightPositionRange; // x、y、z分量為光源的位置,w分量為光源照射范圍的倒數
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 4個光源的x、y、z坐標,注意unity_4LightPosX0中的4個分
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 量分別存儲了4個光源的x坐標,unity_4LightPosY0中的4個
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 分量分別存儲了4個光源的y坐標,其余類推
? ? float4unity_4LightPosX0;
? ? float4unity_4LightPosY0;
? ? float4unity_4LightPosZ0;
? ? half4unity_4LightAtten0; // 4個光源的衰減值
????????上面代碼定義的4個光源,是等級為非重要光源的點光源。這4個光源僅用在前向渲染途徑的base pass中。
????????3. 8個光源的顏色、位置、衰減值和照射方向
????????通過以下代碼定義8個光源的顏色、位置、衰減值和照射方向。
? ? ? // 所在文件:UnityShaderVariables.cginc代碼
? ? ? // 所在目錄:CGIncludes
? ? ? // 從原文件第124行開始,至第130行結束
? ? ? ? ? half4unity_LightColor[8]; // 8個光源的顏色
? ? ? ? ? //有向光的視圖空間頂點光源位置(position,1),或者(-direction,0)
? ? ? ? ? // 在觀察空間中用來在頂點著色器中執行頂點光照計算的光源位置點。如果光源是有向平行光。那么變量中
? ? ? ? ? // 的x、y、z分量存儲著光源的光照射方向的反方向,w分量為0;如果光源是非有向平行光源,那么變量
? ? ? ? ? // 中的x、y、z分量存儲著光源的位置坐標,w分量為1
? ? ? ? ? float4unity_LightPosition[8];
? ? ? ? ? //對于非點光源x = cos(spotAngle/2)或-1
? ? ? ? ? //對于非點光源y = 1/cos(spotAngle/4)或1,注意,代碼中原有的對y分量的注釋,有誤
? ? ? ? ? // z = quadratic attenuation
? ? ? ? ? // w = range*range
? ? ? ? ? half4unity_LightAtten[8];
? ? // 8個光源的正前照射方向,這些方向向量基于觀察空間,如果這些光源不是聚光燈光源,都為(0,0,1,0)
? ? float4unity_SpotDirection[8];
????????Unity 3D技術支持工程師介紹,因為種種原因,在unity_LightAtten變量的原有代碼注釋中,對于y分量的描述其實是錯誤的。y分量的正確值應該是:聚光燈1/4張角的余弦值減去其1/2張角的余弦值。如果該差值不為0,則y為該差值的倒數,否則為1。
????????4. 球諧光照使用到的參數
????????通過以下代碼定義球諧光照使用到的參數。
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第133行開始,至第139行結束
? ? // 球諧光照的相關參數,詳見7.7節中球諧函數的相關理論
? ? half4unity_SHAr;
? ? half4unity_SHAg;
? ? half4unity_SHAb;
? ? half4unity_SHBr;
? ? half4unity_SHBg;
? ? half4unity_SHBb;
? ? half4unity_SHC;
????????5.和光探針相關的參數
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第142行開始,至第144行結束
? ? fixed4unity_OcclusionMaskSelector;
? ? fixed4unity_ProbesOcclusion;
CBUFFER_END
//以下變量從4.0版本開始已棄用。之所以保留它們是為了兼容現有的使用這些變量的第三方著色器
CBUFFER_START(UnityLightingOld)
? ? half3unity_LightColor0, unity_LightColor1, unity_LightColor2, unity_LightColor3;
CBUFFER_END
4.1.4 與陰影相關的著色器常量緩沖區
????????UnityShadows著色器常量緩沖區????????
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第153行開始,至第162行結束
CBUFFER_START(UnityShadows)
? ? // 用于構建層疊式陰影貼圖時子視截體用到的包圍球
? ? float4unity_ShadowSplitSpheres[4];
? ? // unity_ShadowSplitSpheres中4個包圍球半徑的平方
? ? float4unity_ShadowSplitSqRadii;
? ? float4unity_LightShadowBias;
? ? float4_LightSplitsNear;
? ? float4_LightSplitsFar;
? ? // 把某個坐標點從世界空間變換到陰影貼圖空間,如果使用層疊式陰影貼圖
? ? // 數組各元素就表征4個陰影貼圖各自所對應的陰影貼圖空間
? ? float4x4unity_WorldToShadow[4];
? ? half4_LightShadowData;
? ? float4unity_ShadowFadeCenterAndType;
CBUFFER_END
4.1.5 與逐幀繪制調用相關的著色器常量緩沖區
通過以下代碼定義UnityPerDraw著色器常量緩沖區。
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第166行開始,至第171行結束
CBUFFER_START(UnityPerDraw)
? ? float4x4unity_ObjectToWorld;// 把頂點從局部空間變換到世界空間的變換矩陣
? ? float4x4unity_WorldToObject;// 把頂點從世界空間變換到局部空間的變換矩陣
? ? float4unity_LODFade;
? ? float4unity_WorldTransformParams;
? ? //該變量的w分量通常為1,當縮放變量值為負數時,
? ? //常被引擎賦值為-1
CBUFFER_END
4.1.6 與霧效果相關的常量緩沖區
????????通過以下代碼定義UnityFog著色器常量緩沖區。
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第236行開始,至第243行結束
CBUFFER_START(UnityFog)
? ? fixed4unity_FogColor; // 霧的顏色
? ? // x = density / sqrt(ln(2)), 用于霧化因子指數平方衰減
? ? // y = density / ln(2), 用于霧化因子指數衰減
? ? // z = -1/(end-start), 用于霧化因子線性衰減
? ? // w = end/(end-start), 用于霧化因子線性衰減
? ? float4unity_FogParams;
CBUFFER_END
4.1.7 與光照貼圖相關的常量緩沖區
????????通過以下代碼聲明Unity_Lightmap變量。
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第250行開始,至第252行結束
// 聲明了主光照貼圖,該貼圖記錄了直接照明下的光照信息
UNITY_DECLARE_TEX2D_HALF(unity_Lightmap);
// 聲明了間接照明所產生的光照信息,因為unity_LightmapInd和unity_Lightmap
// 搭配使用所以不用另外專門聲明采樣器
UNITY_DECLARE_TEX2D_NOSAMPLER_HALF(unity_LightmapInd);
????????2. UNITY DECLARE TEX2D NOSAMPLER宏的定義
// 所在文件:HLSLSupport.cginc代碼
// 所在目錄:CGIncludes
#if defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) ||
? ? ? defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL)
? ? ? // 中間的若干行代碼省略
? ? ? // 本行代碼在原文件第411行
? ? ? #define UNITY_DECLARE_TEX2D_NOSAMPLER(tex) Texture2D tex
#else
? ? ? // 中間的若干行代碼省略
? ? ? // 本行的代碼在原文件第492行
? ? ? #define UNITY_DECLARE_TEX2D_NOSAMPLER(tex) sampler2D tex
????????3. unity ShadowMask變量的定義
????????unity_ShadowMask變量的定義如下。
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第254行開始,至第261行結束
// 如果啟用了陰影蒙版,陰影蒙版在7.5.2節中有詳細解釋
#if defined (SHADOWS_SHADOWMASK)
? ? ? #if defined(LIGHTMAP_ON) // 如果啟用了光照貼圖
? ? ? ? ? UNITY_DECLARE_TEX2D_NOSAMPLER(unity_ShadowMask);
? ? ? #else
? ? ? ? ? UNITY_DECLARE_TEX2D(unity_ShadowMask);
? ? ? #endif
#endif
????????4.和全局照明光照貼圖相關的變量
// 所在文件:UnityShaderVariables.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第264行開始,至第271行結束
UNITY_DECLARE_TEX2D(unity_DynamicLightmap);
UNITY_DECLARE_TEX2D_NOSAMPLER(unity_DynamicDirectionality);
UNITY_DECLARE_TEX2D_NOSAMPLER(unity_DynamicNormal);
CBUFFER_START(UnityLightmaps)
? ? // 對應于靜態光照貼圖變量unity_Lightmap,用于tiling和offset操作。tiling和offset
? ? // 操作的詳細信息參見4.2.5節,unity_Lightmap變量參見4.1.7節
? ? float4unity_LightmapST;
? ? // 對應于動態(實時)光照貼圖變量unity_DynamicLightmap,用于tiling和offset操作
? ? float4unity_DynamicLightmapST;
CBUFFER_END
????????5.與反射用光探針相關的著色器變量
UNITY_DECLARE_TEXCUBE(unity_SpecCube0);
UNITY_DECLARE_TEXCUBE_NOSAMPLER(unity_SpecCube1);
CBUFFER_START(UnityReflectionProbes)
? ? // 反射用光探針的作用區域立方體是一個和世界坐標系坐標軸軸對齊的包圍盒
? ? // unity_SpecCube0_BoxMax的x、y、z分量存儲了該包圍盒在x、y、z軸方向上的最大邊界值
? ? // 它的值由反射用光探針的Box Size屬性和Box Offset屬性計算而來
? ? float4unity_SpecCube0_BoxMax;
? ? // unity_SpecCube0_BoxMax的x、y、z分量存儲了該包圍盒在x、y、z軸方向上的最小邊界值
? ? float4unity_SpecCube0_BoxMin;
? ? // 對應于ReflectionProbe組件中的光探針位置,它由Transfrom組件的
? ? // Position屬性和Box Offset屬性計算而來
? ? float4unity_SpecCube0_ProbePosition;
? ? // 反射用光探針使用的立方體貼圖中包含高動態范圍顏色,這允許它包含大于1的亮度值
? ? // 在渲染時要將HDR值轉為RGB值
? ? half4 unity_SpecCube0_HDR;
? ? float4unity_SpecCube1_BoxMax;
? ? float4unity_SpecCube1_BoxMin;
? ? float4unity_SpecCube1_ProbePosition;
? ? half4 unity_SpecCube1_HDR;
CBUFFER_END
????????UNITY_DECLARE_TEXCUBE宏在HLSLSupport.cginc文件中定義,用來聲明一個立方體貼圖變量。而UNITY_DECLARE_TEXCUBE_NOSAMPLER宏則是一個不聲明采樣器變量的版本。
????????6.立方體貼圖的聲明變量、對紋理采樣等相關的宏
????????UNITY_SAMPLE_TEXCUBE_LOD宏對立方體紋理貼圖根據當前的mipmap層級進行采樣。
4.2 UnityCG.cginc文件中的工具函數和宏
4.2.1 數學常數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第3行開始,至第13行結束
#ifndef UNITY_CG_INCLUDED
#define UNITY_CG_INCLUDED
#define UNITY_PI 3.14159265359f // 圓周率
#define UNITY_TWO_PI 6.28318530718f // 2倍圓周率
#define UNITY_FOUR_PI 12.56637061436f // 4倍圓周率
#define UNITY_INV_PI 0.31830988618f //圓周率的倒數
#define UNITY_INV_TWO_PI 0.15915494309f // 2倍圓周率的倒數
#define UNITY_INV_FOUR_PI 0.07957747155f // 4倍圓周率的倒數
#define UNITY_HALF_PI 1.57079632679f // 半圓周率
#define UNITY_INV_HALF_PI 0.636619772367f //半圓周率的倒數
4.2.2 與顏色空間相關的常數和工具函數
????????1. IsGammaSpace函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第79行開始,至第86行結束
// 用來判斷當前是否啟用了伽馬顏色空間函數
inline boolIsGammaSpace()
{
#ifdef UNITY_COLORSPACE_GAMMA
? ? return true;
#else
? ? return false;
#endif
}
????????本函數在新版本不再使用,保留它是為了兼容舊版本及很多已經存在的著色器。
????????2.GammaToLinearSpaceExact函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第88行開始,至第96行結束
inline floatGammaToLinearSpaceExact (floatvalue)
{
????????if(value <= 0.04045F)
? ? ? ????????returnvalue / 12.92F;
????????else if(value < 1.0F)
? ? ? ????????returnpow((value + 0.055F)/1.055F, 2.4F);
????????else
? ? ????????returnpow(value, 2.2F);
}
????????GammaToLinearSpaceExact函數把一個顏色值精確地從伽馬顏色空間(sRGB顏色空間)變換到線性空間(CIE-XYZ顏色空間)。
????????3.GammaToLinearSpace函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第98行開始,至第105行結束
inline half3GammaToLinearSpace (half3sRGB)
{
? ? ? // GammaToLinearSpaceExact函數的近似模擬版本
? ? ? returnsRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h);
}
????????GammaToLinearSpace函數是用一個近似模擬的函數把顏色值近似地從伽馬顏色空間變換到線性空間。
????????4.LinearToGammaSpaceExact函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第107行開始,至第117行結束
inline floatLinearToGammaSpaceExact (floatvalue)
{
? ? ? if(value <= 0.0F)
? ? ? ? ? return0.0F;
? ? ? else if(value <= 0.0031308F)
? ? ? ? ? return12.92F * value;
? ? ? else if(value < 1.0F)
? ? ? ? ? return1.055F * pow(value, 0.4166667F) -0.055F;
? ? ? else
? ? ? ? ? returnpow(value, 0.45454545F);
}
????????LinearToGammaSpaceExact函數把一個顏色值精確地從線性空間變換到伽馬顏色空間。
????????5.LinearToGammaSpace函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第119行開始,至第127行結束
inline half3LinearToGammaSpace (half3linRGB)
{
? ? ? linRGB = max(linRGB, half3(0.h, 0.h, 0.h));
? ? ? returnmax(1.055h * pow(linRGB, 0.416666667h) -0.055h, 0.h);
}
????????LinearToGammaSpace函數是用一個近似模擬的函數把顏色值近似地從線性空間變換到伽馬顏色空間。
4.2.3 描述頂點布局格式的結構體
????????1.頂點結構體appdata base
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第51行開始,至第56行結束
structappdata_base {
? ? ? float4vertex : POSITION; ? ? ? // 世界坐標下的頂點坐標
? ? ? float3normal : NORMAL; ? ? ? ? ?// 頂點法線
? ? ? float4texcoord : TEXCOORD0; ? ?// 頂點使用的第一層紋理坐標
? ? ? UNITY_VERTEX_INPUT_INSTANCE_ID ?// 頂點多例化的ID
};
????????UNITY_VERTEX_INPUT_INSTANCE_ID是定義頂點多例化ID用的一個宏。
????????2. 頂點結構體appdata tan
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第58行開始,至第64行結束
structappdata_tan {
? ? ? float4vertex : POSITION; // 世界坐標下的頂點坐標
? ? ? float4tangent : TANGENT; // 頂點切線
? ? ? float3normal : NORMAL; // 頂點法線
? ? ? float4texcoord : TEXCOORD0; // 頂點使用的第一層紋理坐標
? ? ? UNITY_VERTEX_INPUT_INSTANCE_ID // 頂點多例化的ID
};
????????3.頂點結構體appdata full
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第66行開始,至第76行結束
structappdata_full {
? ? ? float4vertex : POSITION; //世界坐標下的頂點坐標
? ? ? float4tangent : TANGENT; // 頂點切線
? ? ? float3normal : NORMAL; // 頂點法線
? ? ? float4texcoord : TEXCOORD0; // 頂點使用的第一層紋理坐標
? ? ? float4texcoord1 : TEXCOORD1; // 頂點使用的第二層紋理坐標
? ? ? float4texcoord2 : TEXCOORD2; // 頂點使用的第三層紋理坐標
? ? ? float4texcoord3 : TEXCOORD3; // 頂點使用的第四層紋理坐標
? ? ? fixed4color : COLOR; // 頂點顏色
? ? ? UNITY_VERTEX_INPUT_INSTANCE_ID // 頂點多例化的ID
};
4.2.4 用于進行空間變換的工具函數
????????1. UnityWorldToClipPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第130行開始,至第133行結束
inline float4UnityWorldToClipPos( in float3pos )
{
? ? ? returnmul(UNITY_MATRIX_VP, float4(pos, 1.0));
}
????????UNITY_MATRIX_VP,即當前觀察矩陣與投影矩陣的乘積。UnityWorldToClipPos函數的作用就是把世界坐標空間中的某一點pos變換到齊次裁剪空間中去。
????????2. UnityViewToClipPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第136行開始,至第139行結束
inline float4UnityViewToClipPos( in float3pos )
{
? ? ? returnmul(UNITY_MATRIX_P, float4(pos, 1.0));
}
????????宏UNITY_MATRIX_P即當前的投影矩陣。UnityViewToClipPos函數的作用就是把觀察坐標空間中的某一點pos變換到齊次裁剪空間中去。
????????3. 參數類型為float3的UnityObjectToViewPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第142行開始,至第145行結束
inline float3UnityObjectToViewPos( in float3pos )
{
? ? ? returnmul(UNITY_MATRIX_V, mul(unity_ObjectToWorld, float4(pos, 1.0))).xyz;
}
????????UnityObjectToViewPos函數的作用就是把模型局部空間坐標系中的某一個點pos,首先變換到世界空間坐標系下,然后變換到觀察空間坐標系下。
????????4. 參數類型為float4的UnityObjectToViewPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第146行開始,至第149行結束
inline float3UnityObjectToViewPos(float4pos)
{
? ? ? returnUnityObjectToViewPos(pos.xyz);
}
????????5. UnityWorldToViewPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第152行開始,至第155行結束
inline float3UnityWorldToViewPos( in float3pos )
{
? ? ? returnmul(UNITY_MATRIX_V, float4(pos, 1.0)).xyz;
}
????????UnityWorldToViewPos函數的作用是把世界坐標系下的一個點pos變換到觀察坐標系下。
????????6. UnityObjectToWorldDir函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第158行開始,至第161行結束
inline float3UnityObjectToWorldDir( in float3dir )
{
? ? ? returnnormalize(mul((float3x3)unity_ObjectToWorld, dir));
}
????????UnityObjectToWorldDir函數的作用是把一個方向向量從模型坐標系變換到世界坐標系下,然后對結果進行單位化。
????????7. UnityWorldToObjectDir函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第164行開始,至第167行結束
inline float3UnityWorldToObjectDir( in float3dir )
{
??returnnormalize(mul((float3x3)unity_WorldToObject, dir));
}
????????UnityWorldToObjectDir函數的作用是把一個方向向量從世界坐標系變換到模型坐標系下,然后對結果進行單位化。
????????8. UnityObjectToWorldNormal函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第170行開始,至第178行結束
inline float3UnityObjectToWorldNormal( in float3norm )
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
? ? ? returnUnityObjectToWorldDir(norm);
#else
? ? ? returnnormalize(mul(norm, (float3x3)unity_WorldToObject));
#endif
}
????????UnityObjectToWorldNormal函數,即把某頂點的法線normal從模型坐標系下變換到世界坐標系下。
????????9. UnityWorldSpaceLightDir函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第181行開始,至第192行結束
inline float3UnityWorldSpaceLightDir( in float3worldPos )
{
#ifndef USING_LIGHT_MULTI_COMPILE
? ? ? ? ? return_WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w;
#else
? ? ? #ifndef USING_DIRECTIONAL_LIGHT // 如果不是平行光
? ? ? ? ? return_WorldSpaceLightPos0.xyz - worldPos;
? ? ? #else
? ? ? ? ? return_WorldSpaceLightPos0.xyz; // 如果是平行光就直接返回
? ? ? #endif
#endif
}
????????10. WorldSpaceLightDir函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第196行開始,至第200行結束
inline float3WorldSpaceLightDir( in float4localPos )
{
// 首先把localPos變換到世界坐標系下,然后調用UnityWorldSpaceLightDir
// 函數計算出連線方向
? ? float3worldPos = mul(unity_ObjectToWorld, localPos).xyz;
? ? returnUnityWorldSpaceLightDir(worldPos);
}
????????本函數在當前版本的Unity 3D中已經不使用,保留下來是為了兼容舊有的第三方著色器代碼。
????????11. ObjSpaceLightDir函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第203行開始,至第215行結束
inline float3ObjSpaceLightDir( in float4v )
{
? ? ? float3objSpaceLightPos = mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz;
#ifndef USING_LIGHT_MULTI_COMPILE
? ? ? returnobjSpaceLightPos.xyz - v.xyz * _WorldSpaceLightPos0.w;
#else
? ? ? #ifndef USING_DIRECTIONAL_LIGHT
? ? ? ? ? returnobjSpaceLightPos.xyz - v.xyz;
? ? ? #else
? ? ? ? ? returnobjSpaceLightPos.xyz;
? ? ? #endif
#endif
}
????????12. UnityWorldSpaceViewDir函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第218行開始,至第221行結束
inline float3UnityWorldSpaceViewDir( in float3worldPos )
{
? ? ? return_WorldSpaceCameraPos.xyz - worldPos;
}
????????UnityWorldSpaceViewDir函數在世界坐標系下計算出某位置點到攝像機位置點worldPos的連線向量。
????????13. WorldSpaceViewDir函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第225行開始,至第229行結束
inline float3WorldSpaceViewDir( in float4localPos )
{
? ? ? float3worldPos = mul(unity_ObjectToWorld, localPos).xyz;
? ? ? returnUnityWorldSpaceViewDir(worldPos);
}
????????本函數在當前版本的Unity 3D中已經不使用,保留下來是為了兼容舊有的第三方著色器代碼。
????????14. ObjSpaceViewDir函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第232行開始,至第236行結束
inline float3ObjSpaceViewDir( in float4v )
{
? ? ? float3objSpaceCameraPos = mul(unity_WorldToObject,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
? ? ? returnobjSpaceCameraPos - v.xyz;
}
????????15. TANGENT SPACE ROTATION宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第239行開始,至第241行結束
#define TANGENT_SPACE_ROTATION \
? ? ? ? ? ? float3binormal = \
? ? ? ? ? ? cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \
? ? ? ? ? ? float3x3rotation = float3x3( v.tangent.xyz, binormal, v.normal )
????????此宏的作用是定義一個類型為float3x3,名字為rotation的3×3矩陣。這個矩陣由頂點的法線、切線,以及與頂點的法線切線都相互垂直的副法線組成,構成了一個正交的切線空間。
4.2.5 與光照計算相關的工具函數
????????1. Shade4PointLights函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第246行開始,至第282行結束
// 本函數將用在ForwardBase類型的渲染通道上。參數lightPosX、lightPosY、lightPosZ的
// 4個分量依次存儲了4個點光源的x坐標、y坐標、z坐標。參數lightColor0、
// lightColor1、lightColor2、lightColor3依次存儲了4個點光源的顏色的RGB值。lightAttenSq的
// 4個分量依次存儲了4個點光源的二次項衰減系數
float3Shade4PointLights(float4lightPosX, float4lightPosY, float4lightPosZ,
? ? ? float3lightColor0, float3lightColor1, float3lightColor2, float3lightColor3,
? ? ? float4lightAttenSq,float3pos, float3normal)
????????Shade4PointLights函數用在頂點著色器的ForwardBase渲染通道上。本函數在每一個頂點被4個點光源照亮時,利用朗伯光照模型(Lambert lighting model)計算出光照的漫反射效果。
????????2. ShadeVertexLightsFull函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第286行開始,至第313行結束
// 本函數用在頂點著色器中,計算出光源產生的漫反射光照效果
// float4 vertex頂點的位置坐標
// float4 normal頂點的位置坐標
// float4 lightCount參與光照計算的光源數量
// float4 spotLight光源是不是聚光燈光源
float3ShadeVertexLightsFull(float4vertex, float3normal,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? intlightCount, boolspotLight)
????????3. ShadeVertexLights函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第315行開始,至第318行結束
float3ShadeVertexLights(float4vertex, float3normal)
{
? ? ? returnShadeVertexLightsFull(vertex, normal, 4, false);
}
4. TRANSFORM TEX宏和TRANSFORM UV宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第435行開始,至第438行結束
#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
#define TRANSFORM_UV(idx) v.texcoord.xy
????????TRANSFORM_TEX即是用頂點中的紋理映射坐標tex與待操作紋理name的Tiling(平鋪值)和Offset(偏移值)做一個運算操作。
????????5. 結構體v2f vertex lit
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第442行開始,至第446行結束
structv2f_vertex_lit {
? ? ? float2uv : TEXCOORD0;
? ? ? fixed4diff : COLOR0;
? ? ? fixed4spec : COLOR1;
};
????????v2f_vertex_lit定義了一個頂點布局格式結構體,該結構體很簡單,只用到了一層紋理,另外指定了兩種顏色,用來模擬漫反射顏色和鏡面反射顏色。
????????Vertex-Lit是實現最低保真度的光照且不支持實時陰影的渲染途徑,最好使用于舊機器或受限制的移動平臺上。
????????6. VertexLight函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第448行開始,至第455行結束
inline fixed4VertexLight( v2f_vertex_lit i, sampler2DmainTex )
{
? ? ? fixed4texcol = tex2D( mainTex, i.uv );
? ? ? fixed4c;
? ? ? c.xyz = ( texcol.xyz * i.diff.xyz + i.spec.xyz * texcol.a );
? ? ? c.w = texcol.w * i.diff.w;
? ? ? returnc;
}
????????VertexLight是一個簡單的頂點光照計算函數,其顏色計算方式就是用頂點漫反射顏色乘以紋理顏色,然后加上紋素的Alpha值與頂點鏡面反射顏色,兩者之和就是最終的顏色。
????????7. ParallaxOffset函數
// 所在文件:UnityCG.cginc
// 所在目錄:CGIncludes
// 從原文件第459行開始,至第465行結束
inline float2ParallaxOffset( halfh, halfheight, half3viewDir )
{
? ? ? h = h * height - height/2.0;
? ? ? float3v = normalize(viewDir);
? ? ? v.z += 0.42;
? ? ? returnh * (v.xy / v.z);
}
????????ParallaxOffset函數根據當前片元對應的高度圖中的高度值h,以及高度縮放系數height和切線空間中片元到攝像機的連線向量,計算到當前片元實際上要使用外觀紋理的哪一點的紋理。
????????8. Luminance函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第468行開始,至第471行結束
inline halfLuminance(half3rgb)
{
? ? ? returndot(rgb, unity_ColorSpaceLuminance.rgb);
}
????????Luminance函數把一個RGB顏色值轉化成亮度值,當前的RGB顏色值基于伽馬空間或者線性空間,得到的亮度值有不同的結果。
????????9.LinearRgbToLuminance函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第475行開始,至第478行結束
// 把在線性空間中的顏色RGB值轉換成亮度值
halfLinearRgbToLuminance(half3linearRgb)
{
? ? ? returndot(linearRgb, half3(0.2126729f,0.7151522f, 0.0721750f));
}
????????LinearRgbToLuminance函數是把一個在線性空間中的RGB顏色值轉換成亮度值。
4.2.6 與HDR及光照貼圖顏色編解碼相關的工具函數
????????高動態范圍(high dynamic range,HDR)光照是一種用來實現超過了顯示器所能表現的亮度范圍的渲染技術。
????????實際的HDR實現一般遵循以下幾步:①在每個顏色通道是16位或者32位的浮點紋理或者渲染目標(float render target)上渲染當前的場景;②使用RGBM、LogLuv等編碼方式來節省所需的內存和帶寬;③通過降采樣(down sample)計算場景亮度;④根據場景亮度值對場景做一個色調映射(tone mapping),將最終顏色值輸出到一個每通道8位的RGB格式的渲染目標上。
????????1. UnityEncodeRGBM函數
????????half4UnityEncodeRGBM (half3color, floatmaxRGBM)
????????RGBM是一種顏色編碼方式,M即shared multiplier。本函數的作用:將顏色數據編碼成一個能以8位顏色分量存儲的數據。
????????2. DecodeHDR函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第497行開始,至第451行結束
inline half3DecodeHDR(half4data, half4decodeInstructions)
????????3. DecodeLightmapRGBM函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第517行開始,至第529行結束
inline half3DecodeLightmapRGBM (half4data, half4decodeInstructions)
????????DecodeLightmapRGBM函數是把一個RGBM顏色值解碼成一個每通道8位的RGB顏色。
????????4. DecodeLightmapDoubleLDR函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第532行開始,至第536行結束
// 解碼一個用dLDR編碼的光照貼圖
inline half3DecodeLightmapDoubleLDR( fixed4color )
????????5. DecodeLightmap函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第538行開始,至第545行結束
inline half3DecodeLightmap( fixed4
color, half4decodeInstructions)
????????6. unity Lightmap HDR變量和DecodeLightmap函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第547行開始,至第552行結束
half4unity_Lightmap_HDR;
inline half3DecodeLightmap( fixed4color )
{
? ? ? returnDecodeLightmap( color, unity_Lightmap_HDR );
}
????????7. DecodeDirectionalLightmap函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第571行開始,至第583行結束
inline half3DecodeDirectionalLightmap(half3color, fixed4dirTex, half3normalWorld)
{
? ? ? // 半朗伯光照模型
? ? ? halfhalfLambert = dot(normalWorld, dirTex.xyz -0.5) + 0.5;
? ? ? // w分量用來控制該點上輻射入射度的方向性,即被dominant方向影響的程度
? ? ? returncolor * halfLambert / max(1e-4h, dirTex.w);
}
????????光照貼圖目前用得比較多而且渲染效果也不錯的實現方法是定向光照貼圖(directional light map),它是原始光照貼圖的增強實現。它主要是通過在預處理與實時還原過程中加入場景中表面的法向量進行運算,進而增強效果。定向光照貼圖技術的大致實現方式如下所示。
????????1)在采樣點處把其所處的半球空間中的輻射入射度用某種方法進行采集并保存。
????????2)以某種方法存儲額外的且與該輻射入射度相關的法線信息到烘焙所得的光照貼圖中。
????????3)在運行時的實時渲染過程中,通過光照貼圖對片元上的場景輻射入射度,并結合光照信息和方向信息進行還原。
????????8. DecodeRealtimeLightmap函數
//該函數對實時生成的光照貼圖進行解碼,Enlighten中間件實時生成的光照貼圖
// 格式不同于一般的Unity 3D的HDR紋理
// 例如,烘焙式光照貼圖、反射用光探針,還有IBL圖像等
// Englithen渲染器的RGBM格式紋理是在線性顏色空間中定
// 義顏色,使用了不同的指數操作
// 要將其還原成RGB顏色需要做以下操作
inline half3DecodeRealtimeLightmap( fixed4color )
4.2.7 把高精度數據編碼到低精度緩沖區的函數
????????EncodeFloatRGBA函數是把一個在區間[0,1]內的浮點數編碼成一個float4類型的RGBA值。
????????DecodeFloatRGBA函數則是EncodeFloatRGBA函數的逆操作。
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第586行開始,至第599行結束
inline float4EncodeFloatRGBA( float v )
// 把一個float4類型的RBGA紋素值解碼成一個float類型的浮點數
inline floatDecodeFloatRGBA( float4enc )
????????2. EncodeFloatRG函數和DecodeFloatRG函數
????????EncodeFloatRG函數與DecodeFloatRG函數的設計思想和EncodeFloatRGBA函數以及Decode FloatRGBA函數一樣,只是使用了兩個通道去進行編碼。
????????3. EncodeViewNormalStereo函數和DecodeViewNormalStereo函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第619行開始,至第637行結束
inline float2EncodeViewNormalStereo( float3n )
inline float3DecodeViewNormalStereo( float4enc4 )
????????EncodeViewNormalStereo函數使用球極投影(stereographic projection)將觀察空間中的物體的法線映射為一個2D紋理坐標值坐標。
????????4. EncodeDepthNormal函數和DecodeDepthNormal函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第639行開始,至第651行結束
inline float4EncodeDepthNormal( floatdepth, float3normal )
inline voidDecodeDepthNormal( float4enc, out floatdepth, out float3normal )
4.2.8 法線貼圖及其編解碼操作的函數
????????法線貼圖(normal map)中存儲的信息是對模型頂點法線的擾動方向向量。利用此擾動方向向量,在光照計算時對頂點原有的法線進行擾動,從而使法線方向排列有序的平滑表面產生法線方向雜亂無序從而導致表面凹凸不平的效果。因為法線貼圖有如此特性,所以在實際應用中需使用“低面數模型+法線貼圖”的方式實現高面數模型才能達到的精細效果。
????????構建切線空間的流程指定了頂點的法線,過頂點有無數條和法線垂直的切線,法線和切線叉乘求得副法線。
????????DXT是一種紋理壓縮格式,以前稱為S3TC。當前很多圖形硬件已經支持這種格式,即在顯存中依然保持著壓縮格式,從而減少顯存占用量。
????????要使用DXT格式壓縮圖像,要求圖像大小至少是4×4紋素,而且圖像高寬的紋素個數是2的整數次冪,如32×32、64×128等。
????????1. UnpackNormal函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第673行開始,至第680行結束
inline fixed3UnpackNormal(fixed4packednormal)
{
#if defined(UNITY_NO_DXT5nm)
? ? ? returnpackednormal.xyz * 2-1;
#else
? ? ? returnUnpackNormalmapRGorAG(packednormal);
#endif
}
????????2. UnpackNormalmapRGorAG函數
????????UnpackNormalRGorAG函數便能同時處理格進DXT5nm或者BC5格式的法線貼圖,并正確地把法線擾動向量從紋素中解碼出來。
????????3. UnpackNormalDXT5nm函數
????????UnpackNormalDXT5nm函數用來解碼DXT5nm格式的法線貼圖,其算法思想和UnpackNormalmap RGorAG函數一致,如下所示。
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第653行開始,至第659行結束
inline fixed3UnpackNormalDXT5nm(fixed4packednormal)
{
? ? ? fixed3normal;
? ? ? normal.xy = packednormal.wy * 2-1;
? ? ? normal.z = sqrt(1- saturate( dot(normal.xy, normal.xy)));
? ? ? returnnormal;
}
4.2.9 線性化深度值的工具函數
????????1. Linear01Depth函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第684行開始,至第687行結束
// 把從深度紋理中取得的頂點深度值z變換到觀察空間中,然后映射到[0,1]區間內
// _ZBufferParams的x分量為1減去視截體遠截面值與近截面值的商,_ZBufferParams的y分量為視截體
// 遠截面值與近截面值的商
inline floatLinear01Depth( floatz )
{
? ? ? return1.0 / (_ZBufferParams.x * z + _ZBufferParams.y);
}
????????2. LinearEyeDepth函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第689行開始,至第692行結束
// 把從深度紋理中取得的頂點深度值z變換到觀察空間中
// _ZBufferParams的z分量為x分量除以視截體遠截面值,w分量為y分量除以視截體遠截面值
inline floatLinearEyeDepth( floatz )
{
? ? ? return1.0 / (_ZBufferParams.z * z + _ZBufferParams.w);
}
????????3. 封裝了操作深度紋理的工具宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第734行開始,至第737行結束
#define DECODE_EYEDEPTH(i) LinearEyeDepth(i)
// 取得頂點從世界空間變換到觀察空間后的z值,并且取其相反數
#define COMPUTE_EYEDEPTH(o) o = -UnityObjectToViewPos( v.vertex ).z
// 取得頂點從世界空間變換到觀察空間后的z值,并且取其相反數后將值映射到[0,1]范圍內
#define COMPUTE_DEPTH_01-(UnityObjectToViewPos( v.vertex ).z * _ProjectionParams.w)
// 把頂點法線從世界空間變換到觀察空間
#define COMPUTE_VIEW_NORMAL normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.normal))
4.2.10 合并單程立體渲染時的左右眼圖像到一張紋理的函數
????????1. TransformStereoScreenSpaceTex函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第707行開始,至第712行結束
#if defined(UNITY_SINGLE_PASS_STEREO)
float2TransformStereoScreenSpaceTex(float2uv, floatw)
{
? ? ? float4scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex];
? ? ? returnuv.xy * scaleOffset.xy + scaleOffset.zw * w;
}
????????TransformStereoScreenSpaceTex函數即對單程立體渲染用到的左右眼圖像,放到一張可渲染紋理的左右兩邊時要做的縮放和偏移操作。
????????2. 參數類型為float2的UnityStereoTransformScreenSpaceTex函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第714行開始,至第717行結束
inline float2UnityStereoTransformScreenSpaceTex(float2uv)
{
? ? ? returnTransformStereoScreenSpaceTex( saturate(uv), 1.0);
}
????????3. 參數類型為float4的UnityStereoTransformScreenSpaceTex函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第719行開始,至第722行結束
inline float4UnityStereoTransformScreenSpaceTex(float4uv)
{
? ? ? return float4(UnityStereoTransformScreenSpaceTex(uv.xy),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? UnityStereoTransformScreenSpaceTex(uv.zw));
}
????????4. UnityStereoClamp函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第723行開始,至第726行結束
// scaleAndOffset的x、y分量包含對紋理的縮放操作參數,z、w分量包含對紋理
// 的偏移操作參數。本函數把原始的uv坐標的u分量限定在縮放范圍內
inline float2UnityStereoClamp(float2uv, float4scaleAndOffset)
????????5. UnityStereoScreenSpaceUVAdjustInternal函數的兩個版本
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第695行開始,至第705行結束
inline float2UnityStereoScreenSpaceUVAdjustInternal(float2uv,float4scaleAndOffset)
{
? ? ? returnuv.xy * scaleAndOffset.xy + scaleAndOffset.zw;
}
inline float4UnityStereoScreenSpaceUVAdjustInternal(float4uv,float4scaleAndOffset)
{
? ? ? return float4(UnityStereoScreenSpaceUVAdjustInternal(uv.xy, scaleAndOffset),
? ? ? ? ? ? ? ? ? ? ? ? ? UnityStereoScreenSpaceUVAdjustInternal(uv.zw, scaleAndOffset));
}
#define UnityStereoScreenSpaceUVAdjust(x, y) \ ? UnityStereoScreenSpaceUVAdjustInternal(x, y)
????????UnityStereoScreen SpaceUVAdjust宏封裝了計算縮放和偏移的UnityStereoScreenSpaceUVAdjustInternal函數。
4.2.11 用來實現圖像效果的工具函數和預定義結構體
????????1. 結構體appdata_img
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第742行開始,至第747行結束
structappdata_img
{
? ? ? float4vertex : POSITION; // 頂點的齊次化位置坐標
? ? ? half2texcoord : TEXCOORD0; // 頂點用到的第一層紋理映射坐標
? ? ? UNITY_VERTEX_INPUT_INSTANCE_ID // 硬件instance id值
};
????????在實現圖像效果時,頂點著色器會用到一些簡單的頂點描述結構體。appdata_img即定義了這樣的結構體。
????????2. 結構體v2f_img
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第749行開始,至第755行結束
structv2f_img
{
? ? ? float4pos : SV_Position; // 要傳遞給片元著色器的頂點坐標,已變換到裁剪空間中
? ? ? half2uv : TEXCOORD0; ? ? ?// 用到的第一層紋理映射坐標
? ? ? UNITY_VERTEX_INPUT_INSTANCE_ID
? ? ? // 立體渲染時的左右眼索引。此宏在UnityInstancing.cginc文件中定義
? ? ? UNITY_VERTEX_OUTPUT_STEREO
};
????????在實現圖像效果時,頂點經過頂點處理階段后,頂點著色器會返回一個結構體傳遞給片元著色器使用。v2f_img即定義了這樣的一個結構體。
????????3. MultiplyUV函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第757行開始,至第761行結束
float2MultiplyUV (float4x4mat, float2inUV) {
? ? ? float4temp = float4(inUV.x, inUV.y, 0, 0);
? ? ? temp = mul(mat, temp);
? ? ? returntemp.xy;
}
????????MultiplyUV函數的功能就是把紋理坐標向量從二維填充到四維,右乘變換矩陣得到結果向量后,再取結果向量的前兩個分量返回。
????????4. 實現圖像效果時的頂點著色器入口函數vert_img
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第763行開始,至第773行結束
v2f_img vert_img( appdata_img v )
{
? ? v2f_img o;
? ? UNITY_INITIALIZE_OUTPUT(v2f_img, o);
? ? UNITY_SETUP_INSTANCE_ID(v);
? ? UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
? ? o.pos = UnityObjectToClipPos (v.vertex);
? ? o.uv = v.texcoord;
? ? returno;
}
4.2.12 計算屏幕坐標的工具函數
????????1. ComputeNonStereoScreenPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第776行開始,至第783行結束
#define V2F_SCREEN_TYPE float4
// float4 pos是在裁剪空間中的一個齊次坐標值
inline float4ComputeNonStereoScreenPos(float4pos)
{
? ? ? float4o = pos * 0.5f;
? ? ? o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;
? ? ? o.zw = pos.zw;
? ? ? returno;
}
????????傳入給ComputeNonStereoScreenPos函數的參數pos是頂點從其局部空間變換到裁剪空間后得到的齊次坐標值。顧名思義,當不使用立體渲染時調用此函數才有效。傳遞給本函數的參數應是一個在裁剪空間中的齊次坐標,一般調用UnityObjectToClipPos函數計算獲得。
ComputeNonStereoScreenPos函數的函數名中雖然帶有ScreenPos,但調用完該函數后,并不會得到某個頂點在經過一系列變換操作后,對應生成的片元在屏幕坐標系下的坐標值。如果要求得在屏幕坐標系下的值,應該使用如下所示代碼求得。
float4 sPos // 經ComputeNonStereoScreenPos函數計算得到的值
float2 vPP; // 視口坐標(view port position)
float2 vPWH; // 視口的高和寬(view Port Width & Height)
vPP = sPos.xy / sPos.w * vPWH;
????????在上面的代碼中,首先把sPos變量的x 、y分量各自除以自身的w分量,該步實質上就是光柵化階段中的透視除法。
????????Unity 3D封裝了一個真正把視口坐標轉換成屏幕像素坐標的UnityPixelSnap函數。
????????4. ComputeScreenPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第785行開始,至第791行結束
inline float4ComputeScreenPos(float4pos)
{
? ? ? float4o = ComputeNonStereoScreenPos(pos);
#if defined(UNITY_SINGLE_PASS_STEREO)
? ? ? o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
#endif
? ? ? returno;
}
????????5. ComputeGrabScreenPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第793行開始,至第806行結束
// 參數pos是一個基于裁剪空間的齊次坐標值
inline float4ComputeGrabScreenPos(float4pos) {
#if UNITY_UV_STARTS_AT_TOP
? ? floatscale = -1.0;
#else
? ? floatscale = 1.0;
#endif
? ? float4o = pos * 0.5f; //第1步
? ? o.xy = float2(o.x, o.y*scale) + o.w;// 第2步
#ifdef UNITY_SINGLE_PASS_STEREO
? ? o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
#endif
? ? o.zw = pos.zw;
? ? returno;
}
????????該函數傳遞進來在裁剪空間中某點的齊次坐標值,返回該點在目標紋理中的紋理貼圖坐標。
????????6. UnityPixelSnap函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第809行開始,至第815行結束
inline float4UnityPixelSnap (float4pos)
{
? ? float2hpc = _ScreenParams.xy * 0.5f;
? ? float2pixelPos = round((pos.xy / pos.w) * hpc);
? ? pos.xy = pixelPos / hpc * pos.w;
? ? returnpos;
}
????????UnityPixelSnap函數的功能是把一個視口坐標轉換成屏幕像素坐標。
????????7. 兩個版本的TransformViewToProjection函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第817行開始,至第823行結束
inline float2TransformViewToProjection (float2v) {
? ? returnmul((float2x2)UNITY_MATRIX_P, v);
}
inline float3TransformViewToProjection (float3v) {
? ? returnmul((float3x3)UNITY_MATRIX_P, v);
}
4.2.13 與陰影處理相關的工具函數
????????1. UnityEncodeCubeShadowDepth函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第817行開始,至第823行結束
float4UnityEncodeCubeShadowDepth(floatz)
{
#ifdef UNITY_USE_RGBA_FOR_POINT_SHADOWS
? ? ? returnEncodeFloatRGBA( min(z, 0.999));
#else
? ? ? returnz;
#endif
}
????????UnityEncodeCubeShadowDepth函數的功能是把一個float類型的陰影深度值編碼進一個float4類型的RGBA數值中。
????????2. UnityDecodeCubeShadowDepth函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第827行開始,至第834行結束
// 把一個從立方體紋理貼圖中獲取到的顏色值轉化為一個深度值
floatUnityDecodeCubeShadowDepth(float4vals)
{
// 如果從一個點光源生成的陰影中獲取到,那么深度值就會被編
// 碼放到R、G、B、A這4個顏色通道中,若再用就要解碼出來
#ifdef UNITY_USE_RGBA_FOR_POINT_SHADOWS
? ? ? returnDecodeFloatRGBA (vals);
#else
? ? ? returnvals.r;
#endif
}
????????UnityDecodeCubeShadowDepth函數的功能是把一個float4類型的陰影深度值解碼到一個float類型的浮點數中。
????????3. UnityClipSpaceShadowCasterPos函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第846行開始,至第870行結束
// vertex,物體頂點在模型空間中的坐標值
// normal,物體法線在模型空間中的坐標值
float4UnityClipSpaceShadowCasterPos(float4vertex, float3normal)
{
? ? ? // 把頂點從模型空間轉換到世界空間
? ? float4wPos = mul(unity_ObjectToWorld, vertex);
? ? if(unity_LightShadowBias.z != 0.0)
{
? ? ? ? ? // 把法線normal從模型空間轉換到世界空間
? ? ? ? ? float3wNormal = UnityObjectToWorldNormal(normal);
? ? ? ? ? //UnityWorldSpaceLightDir函數計算世界坐標系下光源位置點_WorldSpaceLightPos0與
? ? ? ? ? //世界坐標系下點wPos的連線的方向向量_WorldSpaceLightPos0的定義見4.1.3節
? ? ? ? ? float3wLight = normalize(UnityWorldSpaceLightDir(wPos.xyz));
? ? ? ? ? // 計算光線與法線的夾角的余弦值
? ? ? ? ? floatshadowCos = dot(wNormal, wLight);
? ? ? ? ? floatshadowSine = sqrt(1-shadowCos*shadowCos);
? ? ? ? ? // unity_LightShadowBias各分量值詳見4.1.4節
? ? ? ? ? floatnormalBias = unity_LightShadowBias.z * shadowSine;
? ? ? ? ? wPos.xyz -= wNormal * normalBias; // 沿著法線進行偏移
? ? }
? ? returnmul(UNITY_MATRIX_VP, wPos); //把進行了偏移之后的值變換到裁剪空間
}
????????UnityClipSpaceShadowCasterPos函數就是根據法線與光線的夾角的正弦值得到需要的偏移值,然后沿著法線做偏移。
????????4. UnityApplyLinearShadowBias函數
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第878行開始,至第891行結束
float4UnityApplyLinearShadowBias(float4clipPos)
{
// UNITY_REVERSED_Z宏的含義參見4.2.14節
#if defined(UNITY_REVERSED_Z)
? ? ? // 對UnityClipSpaceShadowCasterPos函數計算出來的坐標做一個增加,并且要保證不能越過遠近截面值
? ? ? clipPos.z += max(-1, min(unity_LightShadowBias.x / clipPos.w, 0));
? ? ? floatclamped = min(clipPos.z,clipPos.w*UNITY_NEAR_CLIP_VALUE);
#else
? ? ? clipPos.z += saturate(unity_LightShadowBias.x/clipPos.w);
? ? ? floatclamped = max(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE);
#endif
? ? ? clipPos.z = lerp(clipPos.z, clamped, unity_LightShadowBias.y);
? ? ? // 根據第一次增加后的z值和z的極值,進行線性插值
? ? ? returnclipPos;
}
????????UnityClipSpaceShadowCasterPos函數的功能是將陰影投射者(shadow caster)的坐標沿著其法線做了一定偏移之后再變換至裁剪空間。UnityApplyLinearShadowBias函數的功能是將調用UnityClipSpaceShadowCasterPos函數得到的裁剪空間坐標的z值再做一定的增加。
????????5. V2F SHADOW CASTER NOPOS宏和SHADOW CASTER FRAGMENT宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第894行開始,至第913行結束
#ifdef SHADOWS_CUBE
? ? ? // 用來存儲在世界坐標系下當前頂點到光源位置的連線向量
? ? ? #define V2F_SHADOW_CASTER_NOPOS float3 vec : TEXCOORD0;
? ? ? #define TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,opos) \
? ? ? ? ? o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - \_LightPositionRange.xyz;\
? ? ? ? ? opos = UnityObjectToClipPos(v.vertex);
? ? ? // x、y、z分量為光源的位置,w分量為光源的照射范圍的倒數,TRANSFER_SHADOW_CASTER_NOPOS
? ? ? // 的功能是計算在世界坐標系下當前頂點到光源位置的連線向量,同時把頂點位置變換到裁剪空間。
? ? ? // _LightPositionRange著色器變量參見4.1.3節
#define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) \
? ? ? ? ? o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - \_LightPositionRange.xyz;\
? ? ? ? ? opos = UnityObjectToClipPos(v.vertex);
? ? ? // 把一個float類型的陰影深度值編碼到一個float4類型中并返回
? ? ? #define SHADOW_CASTER_FRAGMENT(i) \
? ? ? ? return UnityEncodeCubeShadowDepth( \
? ? ? ? ? ? ? ? ? ? (length(i.vec) + unity_LightShadowBias.x) * _LightPositionRange.w);
#else
? ? ? // 渲染由平行光或者聚光燈光源產生的陰影
? ? ? #define V2F_SHADOW_CASTER_NOPOS
? ? ? #define V2F_SHADOW_CASTER_NOPOS_IS_EMPTY
? ? ? #define TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,opos) \
? ? ? ? ? opos = UnityObjectToClipPos(v.vertex.xyz); \
? ? ? ? ? opos = UnityApplyLinearShadowBias(opos);
? ? ? #define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) \
? ? ? ? ? // UnityClipSpaceShadowCasterPos函數參見4.2.13節
? ? ? ? ? // UnityApplyLinearShadowBias參見4.2.13節
? ? ? ? ? opos = UnityClipSpaceShadowCasterPos(v.vertex, v.normal); \
? ? ? ? ? opos = UnityApplyLinearShadowBias(opos);
? ? ? #define SHADOW_CASTER_FRAGMENT(i) return 0;
#endif
4.2.14 與霧效果相關的工具函數和宏
????????1. UNITY_Z_0_FAR_FROM_CLIPSPACE宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第945行開始,至第966行結束
#if defined(UNITY_PASS_PREPASSBASE) || defined(UNITY_PASS_DEFERRED) ||
? ? ? defined(UNITY_PASS_SHADOWCASTER)
#undef FOG_LINEAR
#undef FOG_EXP
#undef FOG_EXP2
#endif
#if defined(UNITY_REVERSED_Z)
? ? ? #if UNITY_REVERSED_Z == 1
? ? ? ? ? // 不經Z軸反向操作的OpenGL平臺上的裁剪空間坐標
? ? ? ? ? // 當裁剪空間坐標未經透視除法時,坐標的z值的取值范圍是[0,far];UNITY_RESVERSED_Z
? ? ? ? ? // 啟用了之后,未經透視除法的坐標的z值的取值范圍是[near,0];離當前攝像機越遠其距離值
? ? ? ? ? // 越小,不符合霧化因子的計算方式,所以要將其重新映射到[0,far]為0.1。
? ? ? ? ? // 現令n = _ProjectionParams.y = 0.1,f = _ProjectionParams.z = 100,coord的
? ? ? ? ? // 值為0,計算后得到值為100;令coord的值為0.1,計算后得到值為0;令coord值為0.04,
? ? ? ? ? // 計算后得到值為60,即重新把[0.1,0]的數值映射回[0,100]
? ? ? ? ? #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) \
? ? ? ? ? ? ? ? ? ? ? ? ? max(((1.0-(coord)/
_ProjectionParams.y)*_ProjectionParams.z),0)
? ? #else
? ? ? ? ? // 經過Z軸反向操作的OpenGL平臺上的裁剪空間坐標,z值的取值范圍是[near, -far]因為在
? ? ? ? ? // 實踐操作中,near值通常都會取很小,如0.1等,[near,-far]近似等于[0,-far],所以為了
? ? ? ? ? // 提升性能,直接對坐標值取反即可
? ? ? ? ? #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(-(coord), 0)
? ? #endif
#elif UNITY_UV_STARTS_AT_TOP
? ? // 不經Z軸反向操作的OpenGL平臺上的裁剪空間坐標
? ? // 這時坐標的z值的取值范圍是[0, far],離當前視點越遠距離值越大,所以不用做任何重計算操作
? ? #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#else
? ? // 不經Z軸反向操作的OpenGL平臺上的裁剪空間坐標
? ? // 這時坐標的z值的取值范圍是[-near, far],離當前視點越遠距離值越大,雖然理論上要處理掉深度值
? ? // 為負值的問題,但因為是離當前攝像機越遠距離值越大,霧化因子依然能保持和離當前攝像機距離值的
? ? // 增函數關系,所以不用做任何重計算操作
? ? #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#endif
????????在計算霧化因子時,需要取得當前片元和攝像機的距離的絕對值。而這個距離的絕對值要通過片元在裁剪空間中的z值計算得到。在不同平臺下,裁剪空間的z取值范圍有所不同。所以UNITY_Z_0_FAR_FROM_CLIPSPACE宏就是把各個平臺的差異化給處理掉。
????????2. UNITY_REVERSED_Z宏和UNITY_NEAR_CLIP_VALUE宏
// 所在文件:HLSLSupport.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第626行開始,至第637行結束
// D3D11、PlayStation、XboxOne、Metal、Vulkan、Switch平臺上逆轉裁剪空間的near-far取值即
// near值為1,far為0
#if defined(SHADER_API_D3D11) || defined(SHADER_API_PSSL) ||
? ? ? defined(SHADER_API_XBOXONE) || defined(SHADER_API_METAL) ||
? ? ? defined(SHADER_API_VULKAN) || defined(SHADER_API_SWITCH)
#define UNITY_REVERSED_Z 1
#endif
#if defined(UNITY_REVERSED_Z)
? ? ? #define UNITY_NEAR_CLIP_VALUE (1.0) // near值為1,far值為0
#elif defined(SHADER_API_D3D9) || defined(SHADER_API_WIIU) ||
? ? ? ? defined(SHADER_API_D3D11_9X)
? ? ? // D3D9和D311的9功能級別依然保持near值為0,far值為1
? ? ? #define UNITY_NEAR_CLIP_VALUE (0.0)
#else // 其他平臺,如OpenGL(ES)平臺保持near值為-1,far值為1
? ? ? ? #define UNITY_NEAR_CLIP_VALUE (-1.0)
#endif
????????3. 不同霧化因子計算方式UNITY_CALC_FOG_FACTOR_RAW宏
????????在Other Settings選項中選中Fog復選框后,有Color、Mode、Density這3個選項:Color是霧的顏色,Density是霧的濃度。Mode下拉列表中有Linear、Exponential、Exponential Squared這3個選項,依次對應于啟用FOG_LINEAR、FOG_EXP、FOG_EXP2這3個宏。
FOG_LINEAR? ? // 霧化因子線性化衰減
FOG_EXP? ? ? ???// 霧化因子指數衰減
FOG_EXP2? ? ???// 霧化因子指數衰減
實現方式參考:
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第967行開始,至第979行結束
????????4. UNITY CALC FOG FACTOR宏和UNITY FOG COORDS PACKED宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第981行開始,至第982行結束
#define UNITY_CALC_FOG_FACTOR(coord) \
UNITY_CALC_FOG_FACTOR_RAW(UNITY_Z_0_FAR_FROM_CLIPSPACE(coord))
#define UNITY_FOG_COORDS_PACKED(idx,vectype)vectype fogCoord:TEXCOORD##idx;
????????UNITY_CALC_FOG_FACTOR宏的參數coord是未經透視除法的裁剪空間中的坐標值z分量,封裝了UNITY_CALC_FOG_FACTOR_RAW的實現。參數coord經過宏UNITY_Z_0_FAR_FROM_CLIPSPACE先處理,以解決不同平臺下對應的z軸倒置的問題。
????????UNITY_FOG_COORDS_PACKED宏則是利用頂點格式聲明中的紋理坐標語義,借用一個紋理坐標寄存器把霧化因子聲明在一個頂點格式結構體中。如果使用UNITY_FOG_COORDS_PACKED宏,則在頂點著色器中計算霧化效果。
????????5. 不同平臺和不同霧化因子計算方式下的UNITY TRANSFER FOG宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第983行開始,至第1000行結束
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
? ? ? #define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1)
? ? ? #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)
? ? ? ? ? // 如果使用移動平臺或者使用shade model 2.0的平臺,則在頂點中計算霧化效果
? ? ? ? ? #define UNITY_TRANSFER_FOG(o,outpos) \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? UNITY_CALC_FOG_FACTOR((outpos).z);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? o.fogCoord.x = unityFogFactor
? ? ? #else
? ? ? ? ? // 如果是使用shader model 3.0的平臺,或者使用PC以及一些游戲主機平臺,就在頂點著色
? ? ? ? ? // 器中計算每個頂點離當前攝像機的距離。在片元著色器中計算霧化因子
? ? ? ? ? #define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord.x = (outpos).z
? ? ? #endif
#else
? ? ? #define UNITY_FOG_COORDS(idx)
? ? ? #define UNITY_TRANSFER_FOG(o,outpos)
#endif
????????6. UNITY_FOG_LERP_COLOR宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第1003行開始,至第1003行結束
#define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) \
? ? col.rgb = lerp((fogCol).rgb, (col).rgb, saturate(fogFac))
????????UNITY_FOG_LERP_COLOR宏的功能是利用霧的顏色和當前像素的顏色,根據霧化因子進行線性插值運算,得到最終的霧化效果顏色。
????????7. UNITY_APPLY_FOG_COLOR宏
// 所在文件:UnityCG.cginc代碼
// 所在目錄:CGIncludes
// 從原文件第1004行開始,至第1019行結束
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
? ? #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)
? ? ? ? ? //在移動平臺或者使用shader model 2.0的平臺中,因為霧化因子已經
? ? ? ? ? //在頂點著色器中計算過了,所以直接在片元著色器中插值以計算霧化效果顏色
? ? ? ? ? #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? UNITY_FOG_LERP_COLOR(col,fogCol,(coord).x)
? ? #else
? ? ? ? ? // 如果是PC或者游戲主機平臺,或者是使用shader model 3.0的平臺
? ? ? ? ? // 將在片元著色器中計算霧化因子,然后在片元著色器中通過插值計算霧化效果的顏色
? ? #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol)
UNITY_CALC_FOG_FACTOR((coord).x);\
UNITY_FOG_LERP_COLOR(col,fogCol,unityFogFactor)
? ? #endif
#else
? ? #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol)
#endif
#ifdef UNITY_PASS_FORWARDADD
? #define UNITY_APPLY_FOG(coord,col)
UNITY_APPLY_FOG_COLOR(coord,col,fixed4(0,0,0,0))
#else
? #define UNITY_APPLY_FOG(coord,col)
UNITY_APPLY_FOG_COLOR(coord,col,unity_FogColor)
#endif
????????UNITY_APPLY_FOG_COLOR宏定義在不同平臺上的最終霧化效果的顏色計算方法。