Unity Shader 噪聲消融特效 - 劍靈死亡特效

噪聲是個很神奇的東西,之前接觸的時候就是在自動生成地圖上,由於噪聲原本就近天然因此,不少特效也是基於噪聲的。函數

前幾篇文章介紹了紋理和光照,這回其實也就是用這麼多。就是光照加一個噪聲的法線紋理。動畫

你可能就玩過一款遊戲,劍靈,遊戲中怪物死亡的時候會有一種消融的效果。讓咱們來看一看是怎麼實現的。spa

下面三個圖片分別是BurnAmount = 0、BurnAmount = 0.2五、BurnAmount = 0.5時的效果。code

  

這裏咱們用兩個Pass來處理這個效果orm

  • 第一個Pass:渲染模型的正常顏色和消融的混合顏色
  • 第二個Pass:處理消融的陰影,如不特殊處理則影子不會有消融效果。

下面給出代碼(有必要的註釋)blog

  1 Shader "Shader/Shader"
  2 {
  3     Properties
  4     {
  5         _MainTex ("Main Tex", 2D) = "white" {}
  6         // 法線貼圖
  7         _BumpMap ("Bump Map", 2D) = "bump" {}
  8         // 噪聲貼圖
  9         _BurnMap ("Burn Map", 2D) = "white" {}
 10         // 控制消融程度
 11         _BurnAmount ("Burn Amount", Range(0, 1)) = 0
 12         // 控制模型燒焦效果的線寬
 13         _LineWidth ("Burn Line Width", Range(0.0, 0.2)) = 0.1
 14         // 燒焦邊緣的顏色
 15         _BurnColor ("Burn Color", Color) = (1, 0, 0, 1)
 16     }
 17     SubShader
 18     {
 19         Tags { "RenderType"="Opaque" "Queue"="Geometry" }
 20 
 21         Pass
 22         {
 23             Tags { "LightMode"="ForwardBase" }
 24             
 25             // 全部面都不被剔除,由於消融的時候應該能夠看到物體的內部。
 26             Cull Off
 27 
 28             CGPROGRAM
 29             #pragma vertex vert
 30             #pragma fragment frag
 31             // 爲獲得正確的光照設置的編譯指令
 32             #pragma multi_compile_fwdbase
 33 
 34             #include "Lighting.cginc"
 35             #include "AutoLight.cginc"
 36 
 37             sampler2D _MainTex;
 38             sampler2D _BumpMap;
 39             sampler2D _BurnMap;
 40             float4 _MainTex_ST;
 41             float4 _BumpMap_ST;
 42             float4 _BurnMap_ST;
 43             fixed _BurnAmount;
 44             fixed _LineWidth;
 45             fixed4 _BurnColor;
 46 
 47             struct a2v
 48             {
 49                 float4 vertex : POSITION;
 50                 float3 normal : NORMAL;
 51                 float2 texcoord : TEXCOORD0;
 52                 fixed4 tangent : TANGENT;
 53             };
 54 
 55             struct v2f
 56             {
 57                 float4 pos : SV_POSITION;
 58                 float2 uvMainTex : TEXCOORD0;
 59                 float2 uvBumpMap : TEXCOORD1;
 60                 float2 uvBurnMap : TEXCOORD2;
 61                 // 切線視圖的光照方向
 62                 float3 lightDir : TEXCOORD3;
 63                 float3 worldPos : TEXCOORD4;
 64                 // Shader 陰影宏:用於對陰影紋理採樣的座標
 65                 // 參數:一個可用的差值寄存器的索引值,用世界的頂點座標。即5(從0開始)
 66                 SHADOW_COORDS(5)
 67             };
 68 
 69             v2f vert(a2v v)
 70             {
 71                 v2f o;
 72 
 73                 o.pos = UnityObjectToClipPos(v.vertex);
 74 
 75                 o.uvMainTex = TRANSFORM_TEX(v.texcoord, _MainTex);
 76                 o.uvBumpMap = TRANSFORM_TEX(v.texcoord, _BumpMap);
 77                 o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);
 78 
 79                 TANGENT_SPACE_ROTATION;
 80                 o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
 81                 o.worldPos = UnityObjectToWorldDir(v.vertex);
 82 
 83                 // 陰影宏:在頂點着色器中計算上一步中聲明的陰影紋理座標
 84                 TRANSFER_SHADOW(o);
 85 
 86                 return o;
 87             }
 88 
 89             fixed4 frag(v2f i) : SV_Target
 90             {
 91                 // 取噪聲貼圖進行採樣
 92                 fixed3 burn = tex2D(_BurnMap, i.uvBurnMap);
 93                 // 用於剔除像素點,if (採樣結果-消融程度閥值 > 0) 存留 or 丟棄
 94                 clip(burn.r - _BurnAmount);
 95 
 96                 fixed3 albedo = tex2D(_MainTex, i.uvMainTex).rgb;
 97 
 98                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
 99 
100                 fixed3 tangentLightDir = normalize(i.lightDir);
101                 fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uvBumpMap));
102                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentLightDir, tangentNormal));
103 
104                 // 陰影宏:計算陰影值,最後與漫反射的顏色疊加
105                 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
106 
107                 // smoothsetp(e1,e2,x)平滑過分函數
108                 // 原理:if (x < e1) 結果 = 0
109                 // if (x > e2) 結果 = 1
110                 // if (e1 < x < e2) 結果 = 3 * pow(x, 2) - 2 * pow(x, 3)
111                 // t = 0時,該像素爲正常的模型顏色
112                 // t = 1時,該像素位於消融的邊界處
113                 fixed t = 1 - smoothstep(0.0, _LineWidth, burn.r - _BurnAmount);
114 
115                 // 最終顏色,在消融和正常中差值,係數爲t
116                 fixed3 finalColor = lerp(ambient + diffuse * atten, _BurnColor, t);
117 
118                 return fixed4(finalColor, 1);
119             }
120             ENDCG
121         }
122 
123         // 此Pass是處理陰影的,咱們須要按照正常的Pass的處理來剔除片元或進行頂點動畫。以便陰影能夠和物體正常渲染的結果相匹配。
124         Pass
125         {
126             // 光照模式定義爲陰影
127             Tags { "LightMode"="ShadowCaster" }
128 
129             CGPROGRAM
130             #pragma vertex vert
131             #pragma fragment frag
132             // 處理陰影的編譯指令
133             #pragma multi_compile_shadowcaster
134             
135             #include "UnityCG.cginc"
136 
137             fixed _BurnAmount;
138             sampler2D _BurnMap;
139             float4 _BurnMap_ST;
140 
141             struct a2v
142             {
143                 float4 vertex : POSITION;
144                 float2 texcoord : TEXCOORD0;
145                 float3 normal : NORMAL;
146                 float4 tangent: TANGENT;
147             };
148 
149             struct v2f
150             {
151                 // 定義陰影投射須要定義的變量
152                 V2F_SHADOW_CASTER;
153                 float2 uvBurnMap : TEXCOORD0;
154             };
155             
156             v2f vert (a2v v)
157             {
158                 v2f o;
159 
160                 // 填充V2F_SHADOW_CASTER定義的變量
161                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
162                 o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);
163 
164                 return o;
165             }
166             
167             fixed4 frag (v2f i) : SV_Target
168             {
169                 fixed3 burn = tex2D(_BurnMap, i.uvBurnMap);
170                 
171                 clip(burn - _BurnAmount);
172 
173                 // 讓Unity完成陰影投射
174                 SHADOW_CASTER_FRAGMENT(i)
175             }
176             ENDCG
177         }
178     }
179 }

本文引自Unity Shader 入門精要索引

相關文章
相關標籤/搜索