——20.8.28
這章的內容看了很久,也有很多復雜的內容,中途還有事情耽擱了一會,開學后就繼續好好記錄努力,
我們在游戲中能看到的讓人覺得真實感的來源之一就是真實的光照以及光照所產生的陰影,下面的內容分為兩個部分一個是光照的部分一個是陰影的生成部分,
說到光照在Unity中渲染路徑就是決定光照是以何種方式應用到Shader中的,所以要通過指定Pass通道的渲染路徑型別 “LightMode” 來進行Shader的光照計算,簡單地說就是設定渲染路徑后Unity便會提供對應的光照資訊給用戶進行光照計算,
目前有三種渲染路徑 1)前向渲染 2)延遲渲染(有新的) 3)頂點照明渲染(被拋棄)
當GPU不支持所選擇的渲染路徑則會降級
設定渲染路徑便是在Tags設定 “LightMode” 有以下支持的的標簽

如果沒有指定渲染路徑可能會出錯,因為此時當作為頂點照明渲染路徑,當中的一些光照變數可能就不會被賦值,
一、前向渲染路徑
每進行一次完整的前向渲染路徑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會根據影響該物體的逐像素光源多次呼叫


以上是一些內置的函式和變數
二、頂點照明渲染
頂點照明可在前向渲染中完成,一個頂點照明的Pass最多8個逐頂點光源

三、延遲渲染路徑
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:這章總算是看完了,還留了很多坑,慢慢補把,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/561.html
標籤:其他
