斧式雷基恩的護盾效果
下圖是 異界鎖鏈 斧式雷基恩的護盾效果:
趁著有空,我做了一個類似的實現(xiàn),丟到 github 上去了,地址:https://github.com/fatdogsp/Unity-Force-Field-Effect。
這個效果不難做,我們只需要檢測出護盾的 邊緣 以及護盾和場景的 交界,并依此來調整護盾的 透明度 即可。
下圖是我的第一版實現(xiàn):
和 異界鎖鏈 相比,三角形背面的交界沒了。
如果需要顯示背面交界,我們首先需要 Cull Off,然后把背面的 邊緣強度 設置為 0,只保留背面的 交界強度。
下圖是我添加背面交界后的效果:
好了,下面來看看實現(xiàn)細節(jié)。
透明度的計算公式
我們需要一個 半透明 的shader,邊緣 和 交界 的透明度低,其他地方透明度高。
這里 透明度 的計算方式有參考 Brackeys的教程,有興趣的可以先看一下視頻。
整體流程用 surface shader 來寫的話,代碼如下:
void surf (Input IN, inout SurfaceOutputStandard o)
{
half alpha = ForceFieldAlpha(IN, o);
o.Albedo = half3(0, 0, 0);
o.Metallic = _Metallic;
o.Smoothness = _Smoothness;
o.Occlusion = 1;
o.Emission = _EmissionColor.rgb;
o.Alpha = alpha;
}
ForceFieldAlpha 函數(shù)主要用來計算 透明度,其他都是常規(guī)操作,顏色主要依靠 自發(fā)光。
ForceFieldAlpha 代碼如下:
half ForceFieldAlpha(Input IN, inout SurfaceOutputStandard o)
{
half depthDelta = ComputeDepthDelta(IN);
half fresnel = ComputeFresnel(IN);
half pattern = ComputePattern(IN);
return (depthDelta + fresnel) * pattern * _AlphaStrength;
}
這里涉及到如下三個函數(shù):
ComputeDepthDelta:計算 交界強度。
ComputeFresnel:計算 邊緣強度。
ComputePattern:計算 整體強度 的貼圖效果和UV動畫。
ComputeDepthDelta
我們可以用 當前像素的深度 和 背景像素的深度 做比較,如果深度相距較近,則可以認為是 交界,代碼如下:
inline half ComputeDepthDelta(Input IN)
{
float2 screenUV = IN.screenPos.xy / IN.screenPos.w;
float screenDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, screenUV));
float depth = IN.screenPos.w - _DepthOffset;
float depthDelta = abs(screenDepth - depth);
depthDelta = 1 - depthDelta;
return smoothstep(0, 1, depthDelta);
}
這里提供一個 _DepthOffset,可以對 深度距離 做額外偏移,從而調整 交界 區(qū)域的大小。
ComputeFresnel
關于 邊緣強度 的計算,我們要區(qū)分是正面還是背面,背面的 邊緣強度 永遠為 0。
如果是 fragment shader,我們可以通過 VFace 來區(qū)分正面背面:
fixed4 frag (fixed facing : VFACE) : SV_Target
{
// VFACE input positive for frontbaces,
// negative for backfaces. Output one
// of the two colors depending on that.
return facing > 0 ? _ColorFront : _ColorBack;
}
可惱的是,surface shader 我沒找到類似的設值,這里我通過 dot(IN.viewDir, IN.worldNormal) 的 正負 來判斷正面背面。
當然,這樣判斷有一定的瑕疵,具體可以參考 這篇帖子,不過做為示例,這樣已經(jīng)OK了,下面貼代碼:
只考慮正面
Cull Back
inline half ComputeFresnel(Input IN)
{
half rim = 1 - saturate(dot(IN.viewDir, IN.worldNormal));
return pow(rim, _FresnelPower);
}
正面背面都考慮
Cull Off
inline half ComputeFresnel(Input IN)
{
half rim = dot(IN.viewDir, IN.worldNormal);
rim = lerp(1 - saturate(rim), 0, rim < 0);
return pow(rim, _FresnelPower);
}
ComputePattern
計算出 邊緣強度 和 邊界強度 后,我們把這2個值相加,就可以得到 整體透明度。
這里我們還可以對 整體透明度 做一些貼圖效果,比如下圖:
原理很簡單,把 ComputePattern 的結果和 整體透明度 做 乘法 即可,ComputePattern 的代碼如下:
inline half ComputePattern(Input IN)
{
float2 uv = IN.uv_PatternTex + half2(_PatternOffsetU, _PatternOffsetV) * _Time.y * _ScrollSpeed;
return tex2D(_PatternTex, uv).r;
}
結尾
只要明白原理,代碼還是很簡單的。
當然,這只是基礎功能,如果需要更多特性,可以參考Unity商店的 ForceField Effects 這個插件。
個人主頁
本文的個人主頁鏈接:https://baddogzz.github.io/2020/02/21/Force-Field/。
好了,拜拜!