噪聲是個很神奇的東西,之前接觸的時候就是在自動生成地圖上,由於噪聲原本就近天然因此,不少特效也是基於噪聲的。函數
前幾篇文章介紹了紋理和光照,這回其實也就是用這麼多。就是光照加一個噪聲的法線紋理。動畫
你可能就玩過一款遊戲,劍靈,遊戲中怪物死亡的時候會有一種消融的效果。讓咱們來看一看是怎麼實現的。spa
下面三個圖片分別是BurnAmount = 0、BurnAmount = 0.2五、BurnAmount = 0.5時的效果。code
這裏咱們用兩個Pass來處理這個效果orm
下面給出代碼(有必要的註釋)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 入門精要索引