【Unity Shader】簡單積雪效果的實現
阿新 • • 發佈:2018-12-20
1.前言
公司的專案進入真機除錯階段,體驗了一個月的996模式的正式結束,放假第一天來寫篇部落格
2.實現思路
1.積雪的實現
一般由模型的紋理貼圖和一張積雪的紋理圖混合而成。
//2個取樣結果的差值(1.模型紋理,2.積雪紋理/顏色)
color.rgb = lerp(color, _SnowColor, SnowThreshold);
不過因為沒找到比較合適的積雪紋理圖,作為一名實習生也不好意思讓公司的美術大佬幫我量身定做,所以退而求其實選擇使用顏色-白色作為紋理的替代。
_SnowColor ("Snow Color", Color) = (1.0, 1.0, 1.0, 1.0)
積雪的程度由引數SnowLevel,SnowDepth來共同控制。
float _SnowLevel;
float _SnowDepth;
2.光照
還是使用Lambert漫反射光照模型,上次沒介紹,這裡簡單介紹一下公式吧
其中:
光源顏色
材質漫反射顏色
法線與光源方向點積的正數值
3.程式碼實現
以下是完整的shader程式碼
Shader "Unlit/SnowShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _SnowColor ("Snow Color", Color) = (1.0, 1.0, 1.0, 1.0) _SnowLevel ("Snow Level", Range(0, 1)) = 0 _SnowDepth ("Snow Depth", Range(0, 0.5)) = 0.1 } SubShader{ Tags {"RenderType" = "Opaque"} CGINCLUDE #include "UnityCG.cginc" #include "Lighting.cginc" #include "AutoLight.cginc" sampler2D _MainTex; float4 _MainTex_ST; float4 _SnowColor; float _SnowLevel; float _SnowDepth; struct a2v{ float4 vertex : POSITION; float3 normal : NORMAL; float2 texcoord : TEXCOORD0; }; struct v2f{ float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float3 worldNormal : TEXCOORD1; float3 worldPos : TEXCOORD2; SHADOW_COORDS(3) }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; TRANSFER_SHADOW(o); return o; } fixed4 frag(v2f i) : SV_Target{ //使用Lambert光照模型 //材質漫反射顏色 fixed3 albedo = tex2D(_MainTex, i.uv).rgb; //入射光方向 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); //世界法線 fixed3 worldNormal = normalize(i.worldNormal); //環境光 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; //漫反射光照 fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, -worldLightDir)); //統一光照衰減和陰影 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); //混合光照 fixed3 lightColor = diffuse * atten + ambient; //紋理取樣 fixed4 color = tex2D(_MainTex, i.uv); //計算閾值,以世界法線和垂直方向夾角點積作為積雪厚度判斷標準,引數Snowlevel,SnowDepth一起控制積雪程度 //一般來說,夾角越小(點積值越大)積雪越厚 half SnowThreshold = dot(i.worldNormal, float3(0, 1, 0)) - lerp(1, -1, _SnowLevel); SnowThreshold = saturate(SnowThreshold / _SnowDepth); // SnowThreshold = saturate(_SnowDepth / SnowThreshold); color.rgb = lerp(color, _SnowColor, SnowThreshold); //混合顏色 輸出,這裡把插值函式第三個值置為1,可以得到一種類似卡通風格的渲染(也就是隻有color作為輸出) fixed3 finalColor = lerp(lightColor, color, SnowThreshold); return float4(finalColor, 1); } ENDCG Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } } FallBack "Diffuse" }