——20.8.28緩存
這章的內容看了好久,也有不少複雜的內容。中途還有事情耽擱了一會。開學後就繼續好好記錄努力。app
咱們在遊戲中能看到的讓人以爲真實感的來源之一就是真實的光照以及光照所產生的陰影。下面的內容分爲兩個部分一個是光照的部分一個是陰影的生成部分。ide
說到光照在Unity中渲染路徑就是決定光照是以何種方式應用到Shader中的。因此要經過指定Pass通道的渲染路徑類型 「LightMode」 來進行Shader的光照計算。簡單地說就是設定渲染路徑後Unity便會提供對應的光照信息給用戶進行光照計算。函數
目前有三種渲染路徑 1)前向渲染 2)延遲渲染(有新的) 3)頂點照明渲染(被拋棄)工具
當GPU不支持所選擇的渲染路徑則會降級性能
設置渲染路徑即是在Tags設定 「LightMode」 有如下支持的的標籤 測試
若是沒有指定渲染路徑可能會出錯,由於此時看成爲頂點照明渲染路徑,當中的一些光照變量可能就不會被賦值。ui
1、前向渲染路徑spa
每進行一次完整的前向渲染路徑1.咱們須要渲染該對象的渲染圖元2.計算兩個緩衝區的信息 a.深度緩衝區(決定是否可見)b.顏色緩衝區(若可見,更新顏色緩衝區)對燈光範圍內的物品每個燈光處理一次執行一次Pass設計
三種處理光照的方式 1)逐頂點處理 2)逐像素處理 3)球諧函數(SH)
一種光源的處理方式由類型和渲染模式(是否重要的,RenderMode)渲染一個物體要對光源進行排序(對物體的影響程度)要遵循如下規則 1)場景中最亮的平行光老是按逐像素處理2)渲染模式被設置爲Not Important按逐頂點或是SH 3)渲染模式被設置爲Important按逐像素處理 4)若是按以上規則獲得的逐像素光源數量小於Quality Setting(PixelLight Count)將會由更多的光源按照逐像素處理
注意事項:1.BasePass支持的光照特性 2.BasePass渲染的平行光默認有燈光 AddtivePass渲染的光源默認狀況下沒有陰影(即便設置了ShadowType)能夠經過 #pragma multi_compile_fwdadd_fullshadows 代替 #pragma multi_compile_fwdadd 爲點光源和聚光燈開啓陰影 3.環境光(環境光和平行光不一樣)和自發光在BasePass計算由於只計算一次在AdditivePass會致使屢次疊加 4.AdditivePass還要開啓混合否則只有一個光源的影響 5.一個BassPass可定義屢次(好比雙面渲染)但只運行一遍而AdditivePass會根據影響該物體的逐像素光源屢次調用
以上是一些內置的函數和變量
2、頂點照明渲染
頂點照明可在前向渲染中完成,一個頂點照明的Pass最多8個逐頂點光源
3、延遲渲染路徑
G緩衝 存儲了離攝像機最近的表面的其餘信息 包含兩個單元第一個Pass計算哪些片元可見,第二個Pass利用G緩衝區中的信息光照計算。效率取決於場景的複雜度,而取決於屏幕空間大小。
優勢 1)場景中的光源數目多,用前向渲染會形成性能瓶頸 2)每一個光源採用逐像素處理 缺點 1)不支持抗鋸齒 2)不能處理半透明 3)對顯卡由需求
分析完渲染路徑以後咱們簡單過一下基礎的燈光類型在unity中存在的燈光類型以及它所具備的特色以及屬性 1)平行光(不存在衰減 面向全局)2)點光源(邊緣的強度爲0,中間的衰減值能夠用函數表示)3)聚光燈(同上,衰減計算更加複雜)4)面光源(只有烘培有用) 燈光所具備的基本特性 1)位置 2)方向 3)顏色 4)強度 5)衰減(到某點的衰減與距離有關)
UnityShader這本書只有對前向渲染有具體的內容,這裏留一個延遲渲染路徑的小坑(?)
主要就是注意要添加一個庫「AutoLight.cginc」 其中有對以前對應渲染路徑的內置變量定義,不然就找不到 好比_LightMatrix0之類
#ifdef USING_DIRECTIONAL_LIGHT fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // normalize(_WorldSpaceLightPos0.xyz); #else fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz); #endif
這部分是在AdditivePass中的中區分平行光以及其餘光源的光源方向。
#ifdef USING_DIRECTIONAL_LIGHT fixed atten = 1.0; #else float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz; fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; //atten = 1.0; #endif
這裏部分是最重要的這部分是在AdditivePass中對衰減的定義。在BasePass由於主要逐像素處理一個最重要的平行光 而平行光不存在衰減因此atten爲1 而在AdditivePass須要區分平行光和其餘光源 點光源採用對應函數進行衰減。在Unity中爲了方便使用一張衰減紋理_LightTexture0來爲光源計算衰減,首先要把對應距離燈光的點經過座標運算從世界到光源空間。而後經過點乘也就是頂點距離的平方來進行紋理取樣。來避免開方計算。上面的".rr"至關因而取x並定義float2(x,x)用於取樣。UNITY_ATTEN_CHANNEL是衰減值所在的衰減通道。咱們不妨看一下這張_LightTexture0是什麼樣的圖,就能理解爲何要平方以後再取樣。
這張圖就是按照平方值設計的。能夠放到畫圖工具中發現它不是線性的。實際至關於一維座標。由於只有x。
實際上這麼分實際上是不夠的由於其餘燈光的聚光燈的衰減是不同的。這裏暫時留一下(?)
// Upgrade NOTE: replaced '_LightMatrix0' with 'unity_WorldToLight' Shader "Unlit/9-1ForwardRendering" { Properties { _Diffuse("Diffuse", Color)= (1,1,1,1) _Specular("Specular", Color)= (1,1,1,1) _Gloss("Gloss", Range(8.0, 256))= 8 } SubShader { Pass { Tags { "LightMode"="ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "Lighting.cginc" #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; }; fixed4 _Diffuse; fixed4 _Specular; float _Gloss; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal = normalize(i.worldNormal); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss); fixed atten = 1.0; return fixed4(ambient + (diffuse + specular) * atten, 1.0); } ENDCG } Pass { Tags{ "LightMode"="ForwardAdd" } Blend One One CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdadd #include "Lighting.cginc" #include "UnityCG.cginc" #include "AutoLight.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; }; fixed4 _Diffuse; fixed4 _Specular; float _Gloss; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); #ifdef USING_DIRECTIONAL_LIGHT fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); #else fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz); #endif fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss); #ifdef USING_DIRECTIONAL_LIGHT fixed atten = 1.0; #else float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz; fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; //atten = 1.0; #endif return fixed4((diffuse + specular) * atten, 1.0); } ENDCG } }FallBack "Specular" }
主要就是在以前的光照模型上區分了BasePass以及AdditivePass,須要指定渲染路徑以及添加對應的#pragma。最後最主要的是增長燈光的衰減。咱們能夠看一下實際效果。經過改變點光源的atten。足以看出衰減的真實感。衰減也能夠用公式不用取樣。同樣後面繼續研究(?)老留坑專家了。
接下來即是最使人頭大的陰影了。但又是最不可獲取的部分。書中的理解部分會居多。
咱們先看一個概念ShadowMap。就是把攝像機放到光源重合的位置而後場景中的陰影就是攝像機看不見的位置。 (本質上是爲了獲得光源空間的深度圖)
在前向渲染中,平行光開啓陰影就會計算它的陰影映射紋理(shadowmap)。實際上他是一張深度圖(mark一下後面的仔細研究一下深度的應用?)記錄了從光源位置出發能看到離他位置最近的表面位置也就是深度信息。那具體是怎麼判斷距離光源最近的表面呢?有如下兩種方法。1)就是用上面的這個ShadowMap方法,把攝像機放到光源位置而後經過前向渲染的BasePass/AdditivePass更新深度信息。可是使用這種正常渲染方式其中涉及狠毒複雜的光照模型計算因此很浪費 2)使用額外的Pass 「LightMode」=「ShadowCaster」 渲染目標是陰影映射紋理不是幀緩存。首先同樣是把攝像機放到光源位置而後調用該Pass(此事得到的深度信息是光源空間,由於和光源重合)。介紹了上述兩個得到表面的方法,在unity中首先會a.找該Pass b.而後找FallBake(由於FallBack定義的默認Shader會有對陰影定義的ShadowCaster通道) c.若是都沒有就沒有陰影。
而後到了最後一步就是得到了對應的深度怎麼把它應用到陰影上。陰影映射技術就是咱們須要看的 主要是由兩種方法 1.傳統方法,把正常的頂點座標轉換到光源空間,而後用xy份量對陰影映射紋理取樣。若是深度小於改頂點的深度值也就是z份量則在陰影裏。 2.屏幕空間的陰影投射技術。用陰影映射紋理以及攝像機(相機擺放位置即Game視圖)的深度紋理經過這兩張圖獲得屏幕空間的陰影圖。攝像機記錄的表面深度深度>其轉換到陰影紋理的深度即爲可見,但在該燈源的陰影中。而後對陰影圖採樣。
因此總結一下 兩個過程 1.咱們想要讓物體接受其餘物體的陰影咱們就要對陰影圖採樣而後於光照結果相乘。2.咱們想要一個物體向其餘物體投射陰影則須要把該物體加入陰影映射紋理的計算中。咱們下面進入實踐過程。
咱們能夠看到這張圖發現有一點奇怪,物品命名有陰影可是這個平面卻沒有。主要緣由是平面在unity中只有一面渲染另外一面不渲染。因此解決方法即是改變平面的MeshRenderer中的CastShadow爲TwoSides才能獲得正確的陰影。
咱們看一下這張圖發現這個方塊沒有接受到平面的陰影但本身卻有陰影並且在Unity設置是正確的即有開啓CastShadow 實際上之因此方塊有陰影是由於採用了FallBack中的「ShadowCaster」的通道可是咱們能夠從上圖得知平面想要投射陰影須要加入陰影投射紋理。其實是輸出片元的時候沒有采樣陰影映射紋理。咱們能夠經過FrameBugger觀察它的深度圖。
上面兩張圖是同樣的陰影圖。可是在渲染方塊的時候卻不同。
SHADOW_COORDS(2)//在v2f中的定義 TRANSFER_SHADOW(o);//在vert中 //在frag中 fixed shadow = SHADOW_ATTENUATION(i); return fixed4(ambient + (diffuse + specular) * atten * shadow, 1.0);
首先SHADOW_COORDS(2)用於對陰影採樣紋理的座標裏面的索引值是2也就對應的是TEXCOORD2.在片元函數中的就是進行陰影映射技術把信息存儲到_ShadowCrood。SHADOW_ATTENUATION對紋理進行採樣。要注意結構體的命名可能會致使定義的宏不可用。
// Upgrade NOTE: replaced '_LightMatrix0' with 'unity_WorldToLight' // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' Shader "Unlit/9-2Shadow" { Properties { _Diffuse ("Diffuse", Color) = (1, 1, 1, 1) _Specular ("Specular", Color) = (1, 1, 1, 1) _Gloss ("Gloss", Range(8.0, 256)) = 20 } SubShader { Tags { "RenderType"="Opaque" } Pass { Tags { "LightMode"="ForwardBase" } CGPROGRAM #pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "AutoLight.cginc" #include "Lighting.cginc" #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNoraml : TEXCOORD0; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2) }; fixed4 _Specular; fixed4 _Diffuse; float _Gloss; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNoraml = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex); TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 worldNoraml = normalize(i.worldNoraml); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNoraml, worldLightDir)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 halfDir = normalize(viewDir + worldLightDir); fixed3 specular = _LightColor0.rgb * _Specular * pow(saturate(dot(worldNoraml, halfDir)), _Gloss); fixed atten = 1.0; fixed shadow = SHADOW_ATTENUATION(i); return fixed4(ambient + (diffuse + specular) * atten * shadow, 1.0); } ENDCG } Pass { Tags { "LightMode"="ForwardAdd" } Blend One One CGPROGRAM #pragma multi_compile_fwdadd #pragma multi_compile_fwdadd_fullshadows #pragma vertex vert #pragma fragment frag #include "AutoLight.cginc" #include "Lighting.cginc" #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNoraml : TEXCOORD0; float3 worldPos : TEXCOORD1; }; fixed4 _Specular; fixed4 _Diffuse; float _Gloss; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNoraml = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 worldNoraml = normalize(i.worldNoraml); #ifdef USING_DIRECTIONAL_LIGHT fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); #else fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz); #endif fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNoraml, worldLightDir)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 halfDir = normalize(viewDir + worldLightDir); fixed3 specular = _LightColor0.rgb * _Specular * pow(saturate(dot(worldNoraml, halfDir)), _Gloss); #ifdef USING_DIRECTIONAL_LIGHT fixed atten = 1.0; #else float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz; fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; #endif return fixed4((diffuse + specular) * atten , 1.0); } ENDCG } }FallBack "Specular" }
如今咱們就有平面的投影了。
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
這個函數是能夠直接統一管理衰減以及陰影。不須要定義atten能夠直接用。
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' Shader "Unlit/9-3AttenuationAndShadowUseBuildInFunc" { Properties { _Diffuse ("Diffuse", Color) = (1, 1, 1, 1) _Specular ("Specular", Color) = (1, 1, 1, 1) _Gloss ("Gloss", Range(8.0, 256)) = 20 } SubShader { Tags { "RenderType"="Opaque" } Pass { Tags { "LightMode"="ForwardBase" } CGPROGRAM #pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2) }; fixed4 _Diffuse; fixed4 _Specular; float _Gloss; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex); TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); fixed3 halfDir = normalize(viewDir + worldLightDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss); UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); return fixed4(ambient + (diffuse + specular) * atten, 1.0); } ENDCG } Pass { Tags { "LightMode"="ForwardAdd" } CGPROGRAM #pragma multi_compile_fwdadd #pragma multi_compile_fwdadd_fullshadows #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; SHADOW_COORDS(2) }; fixed4 _Diffuse; fixed4 _Specular; float _Gloss; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex); TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); fixed3 halfDir = normalize(viewDir + worldLightDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal, halfDir)), _Gloss); UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); return fixed4((diffuse + specular) * atten, 1.0); } ENDCG } } }
這樣BasePass和AdditivePass就能夠統一。
最後就是上一節的一個小坑也是填上了。就是半透明物體的陰影關係。
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' Shader "Unlit/9-4AlphaTestWithShadow" { Properties { _Color("Color", Color) = (1,1,1,1) _MainTex ("Texture", 2D) = "white" {} _Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5 } SubShader { Tags { "RenderType"="TransparentCutOut" "IgnoreProjector"="True" "Queue"="AlphaTest" } Pass { Tags{ "LightMode"="ForwardBase" } Cull Off CGPROGRAM #pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; float2 uv : TEXCOORD2; SHADOW_COORDS(3) //TEXCOORD3 }; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Color; fixed _Cutoff; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texColor = tex2D(_MainTex, i.uv); clip(texColor.a - _Cutoff); fixed3 albedo = texColor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal, worldLightDir)); UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); return fixed4(ambient + diffuse * atten, 1.0); } ENDCG } }
//FallBack "VertexLit"
FallBack "Transparent/Cutout/VertexLit" }
首先是透明測試的投影。效果圖以下。圖一是表示可以正常的接受陰影。圖二圖三分別是採用不一樣的FallBack的效果後者相對於前者是比較正確的。最後一張圖是是否打開CastShadow中的TwoSides左邊是打開的能夠看出正方形的內部投影是和左邊相比體現了處理。
最後是透明度混合的陰影。一樣的增長FallBack
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Unlit/9-5AlphaBlendWithShadow" { Properties { _Color ("Color Tint", Color) = (1, 1, 1, 1) _MainTex ("Main Tex", 2D) = "white" {} _AlphaScale ("Alpha Scale", Range(0, 1)) = 1 } SubShader { Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} Pass { Tags { "LightMode"="ForwardBase" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; fixed _AlphaScale; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; float2 uv : TEXCOORD2; SHADOW_COORDS(3) }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); // Pass shadow coordinates to pixel shader TRANSFER_SHADOW(o); return o; } fixed4 frag(v2f i) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texColor = tex2D(_MainTex, i.uv); fixed3 albedo = texColor.rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir)); // UNITY_LIGHT_ATTENUATION not only compute attenuation, but also shadow infos UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); return fixed4(ambient + diffuse * atten, texColor.a * _AlphaScale); } ENDCG } } //FallBack "Transparent/VertexLit" // Or force to apply shadow FallBack "VertexLit" }
採用FallBack "VertexLit"會強制投影同時接受陰影。"Transparent/VertexLit"二者都不會。主要是半透明物體因爲關閉了深度寫入也會影響對應陰影的生成。
這就是最後了。感謝您讀到這裏。Cheers!
PS:這章總算是看完了。還留了不少坑。慢慢補把。