冰冻效果Shader案例
老規矩先上圖
最近我在設計一個星球題材的獨立游戲,其中一個特色是讓怪物逐漸被冰凍,并在其下方生成冰柱的特效。在這里,我想和大家分享一下我的設計過程。
文章目錄
- 一、貼合冰面
- 二、冰凍起始點
- 三、連貫性逐漸冰凍
- 四、下垂的冰柱
- 五、半螢光效果
- 六、下面是完整代碼:
一、貼合冰面
首先這個特效需要和與原模型緊密貼合,需要將源模型基礎上沿著法線方向向外擴大一些,以避免與原模型有交錯。具體代碼如下:
//因為是疊加在原本的材質上使用的,所以需要比原本的稍微大一些,我們使用向法線方向延展的方式 v.vertex += downNormal * stepNormal + _BaseVectorNormalScale*v.normal;二、冰凍起始點
假設你要做的是一個類似冰凍槍的功能,射擊后從擊中點開始結冰,使用RaycastHit.textureCoord可以獲得擊中點的UV值,賦值給_CenterUv屬性。
三、連貫性逐漸冰凍
一般來說 UV 具有一定的連續性,這里可以將 UV 圖中某一點作為圓心點,向外逐漸展開,以達到逐漸冰凍的效果。具體的實現方法是計算指定 UV 點與起點的距離,逐漸增大其值以達到效果。
//主圖 half4 var_MainTex = tex2D(_MainTex, i.uv0); //高光遮蔽圖(用于區分哪部分有貼圖內容) half4 var_OcclusionTex = tex2D(_OcclusionTex, i.uv0); //_CenterUv是指定中心,計算uv與中心點的距離,能修修改顯示距離達到向外擴展效果 half dic =1- distance(i.uv0.xy, _CenterUv.xy)* var_OcclusionTex; clip(dic- _ClipNum);四、下垂的冰柱
我們需要制作一種向下的冰柱,可以先使用云彩圖制作隨機擾動效果,這些隨機效果的色值通常為0-1。在這里,只有超過0.45的圖案部分才能形成向下的冰柱。
為了讓冰柱看起來更流暢,我們可以在頂點中使用o.nDirWS.g屬性,這將根據冰柱方向下降的程度來調整每個頂點的Y坐標。
因此,在確定了UV映射后,我們需要將超過0.45的頂點向上移動指定的距離,這將產生類似于冰柱的形狀。
五、半螢光效果
通常,在冰面上通常會存在一些凹凸不平的效果。我們可以使用貼圖來模擬這些效果。此外,有時冰面還會有一些閃閃發光的效果。在這種情況下,我們可以使用菲涅爾光來進行模擬。
六、下面是完整代碼:
這里付上完整代碼,大家可以結合代碼和上面的講解會更好理解。也可以擴展成更多的效果,希望對大家有幫助,謝謝。
Shader "Custom/IceAnimStandard" {Properties{[Header(Ground_Base)]_MainTex("基礎色 ",2D) = "white"{}_CloudTex("干擾圖 ",2D) = "white"{}_BaseColor("基礎色",Color) = (1.0,1.0,1.0,1.0)_NormMap("法線貼圖",2D) = "bump"{}[Header(Normal)]_NormalScale("法線縮放",Range(0.0,1)) = 1_VectorNormalScale("頂點法線縮放",Range(0,0.1)) = 0_BaseVectorNormalScale("基礎頂點法線縮放",Range(0,1)) = 0.06[Header(Ground_Diffuse)]_EnvDiffInt("環境漫反射強度",Range(0,1)) = 0.2[Header(Ground_Specular)]_FresnelPow("菲涅爾次冪",Range(0,10)) = 1_FresnelInt("菲涅爾強度",Range(0,2)) = 1_SpecPow("高光次冪",Range(0,5)) = 30_EnvSpecInt("環境鏡面反射強度",Range(0,5)) = 0.2_OcclusionTex("高光遮蔽",2D) = "white"{}_CenterUv("裁剪中心",Vector)=(0.5,0.5,0,0)_ClipNum("裁剪數值",Range(0,1)) = 1}SubShader{Tags{"RenderType" = "Opaque" "IgnoreProjector" = "True"}//Pass{Tags{"LightMode" = "ForwardBase"}//ZWrite off//Cull offCGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"#include "UnityCG.cginc"#pragma target 3.0#pragma multi_compile_fwdbase//地面參數uniform sampler2D _MainTex;uniform sampler2D _CloudTex;uniform sampler2D _NormMap; uniform half4 _NormMap_ST;uniform half4 _BaseColor;uniform half _NormalScale;uniform half _VectorNormalScale;uniform half _BaseVectorNormalScale;uniform half _EnvDiffInt;uniform half _SpecPow;uniform half _EnvSpecInt;uniform half _FresnelPow;uniform half _FresnelInt;uniform sampler2D _OcclusionTex;uniform half2 _CenterUv;uniform half _ClipNum;//輸入結構struct a2v {float4 vertex: POSITION; //頂點信息float2 uv0: TEXCOORD0; //UV信息float4 normal: NORMAL; //法線信息float4 tangent: TANGENT; //切線信息};//輸出結構struct v2f {float4 pos:SV_POSITION; //屏幕定點位置float2 uv0:TEXCOORD0; //UV(不可動)保持默認float2 uv2:TEXCOORD2; //法線UV(用于重復平鋪)float3 WorldPos:TEXCOORD7; //世界坐標位置float3 nDirWS:TEXCOORD4; //世界坐標法線float3 tDirWS:TEXCOORD5; //世界坐標切線float3 bDirWS:TEXCOORD6; //世界坐標副切線SHADOW_COORDS(3)};v2f vert(a2v v) {v2f o; //新輸出結構o.nDirWS = UnityObjectToWorldNormal(v.normal); //法線位置 OS>WShalf h = tex2Dlod(_CloudTex, float4(v.uv0.xy, 0, 0)).r;half stepNormal = step(h,0.45)*_VectorNormalScale*max(0,(_VectorNormalScale - o.nDirWS.g));half4 downNormal = -half4(o.nDirWS,0);downNormal.y = max(0.1, downNormal.y);downNormal.x = 0;downNormal.z = 0;v.vertex += downNormal * stepNormal + _BaseVectorNormalScale*v.normal;o.pos = UnityObjectToClipPos(v.vertex); //頂點位置 OS>CSo.uv0 = v.uv0; //傳弟UVo.uv2 = v.uv0 *_NormMap_ST.xy + _NormMap_ST.zw; //傳弟UVo.WorldPos = mul(unity_ObjectToWorld, v.vertex); //點位置 CS>WSo.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz,0)).xyz); //切線方向o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS)*v.tangent.w); //副切方向TRANSFER_SHADOW(o);return o;}float4 frag(v2f i) :SV_TARGET{//紋理采樣half4 var_MainTex = tex2D(_MainTex, i.uv0);half4 var_OcclusionTex = tex2D(_OcclusionTex, i.uv0);half dic =1- distance(i.uv0.xy, _CenterUv.xy)* var_OcclusionTex;clip(dic- _ClipNum);var_MainTex.rgb *= _BaseColor;//向量準備float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);float4 var_normapTex = tex2D(_NormMap,i.uv2);float3 nDirTS = UnpackNormal(var_normapTex).rgb;float3 nDirTSOrigin = normalize(mul(nDirTS, TBN));nDirTS.xy *= (_NormalScale - (abs(i.uv0.y - 0.5)*(_NormalScale)));nDirTS.z = max(0.5, sqrt(1.0 - saturate(dot(var_normapTex.xy, var_normapTex.xy))));float3 nDirWS = normalize(mul(nDirTS, TBN));float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.WorldPos.xyz);float3 lDirWS = _WorldSpaceLightPos0.xyz;float3 lrDirWS = reflect(-lDirWS,nDirWS);//中間量準備float ndotl = max(0.5, dot(nDirWS, lDirWS));float vdotr = dot(vDirWS, lrDirWS);float vdotn = dot(vDirWS, nDirWS);//光照模型//光源漫反射half3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;half3 baseCol = var_MainTex.rgb*ambient*_LightColor0;//half lambert = max(0.0, ndotl);//光源鏡面反射half specPow = _SpecPow;half phong = pow(max(0.0,vdotr), _SpecPow);//光源反射混合half3 baseLighting = (baseCol + phong * _EnvSpecInt);//(baseCol * lambert + phong * _EnvSpecInt)//環境漫反身half3 envDiff = baseCol * _EnvDiffInt;half upMask = max(0.0, nDirTSOrigin.g);//環境鏡面反射half3 fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow) * _FresnelInt*ambient.rgb;//菲涅爾half3 envSpec = fresnel * _EnvSpecInt*ambient;//環境反射混合half3 envLighting = (envDiff + envSpec)*ambient*_LightColor0;//最終混合half3 finalRGB = (baseLighting+envLighting + fresnel )* var_OcclusionTex.r;// ;*(1 - scale)//返回值//陰影衰減UNITY_LIGHT_ATTENUATION(atten, i, i.WorldPos);return half4((finalRGB)*atten,1);}ENDCG}}FallBack "Diffuse" }總結
以上是生活随笔為你收集整理的冰冻效果Shader案例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二维码的前世今生 与 六大测试点梳理
- 下一篇: OSChina 周二乱弹 ——有一天你当