做房產應看的網站下載微信
本系列為作者學習UnityShader入門精要而作的筆記,內容將包括:
- 書本中句子照抄 + 個人批注
- 項目源碼
- 一堆新手會犯的錯誤
- 潛在的太監(jiān)斷更,有始無終
我的GitHub倉庫
總之適用于同樣開始學習Shader的同學們進行有取舍的參考。
文章目錄
- 使用噪聲
- 上節(jié)補充:smoothstep
- 消融效果
- 水波效果
- 全局霧效
使用噪聲
在有些時候,向規(guī)則的事物里面添加一些雜亂無章的效果,往往會有奇效。而這些雜亂無章的效果的來源就是噪聲。在本章中我們將學習如何使用噪聲來模擬一些特效。
上節(jié)補充:smoothstep
這篇文章很好的描述了smoothstep實現了什么樣的效果。實際實現了對一個圓形范圍的邊緣模糊Shader實驗室: smoothstep函數
消融效果
消融效果往往使用在角色死亡,地圖燒毀等現象上。消融的效果往往是從不同區(qū)域開始,然后往看似隨機的方向擴散,最后整個物體消失不見。
Shader
Shader "Custom/Dissolve_Copy"
{Properties{_BurnAmount ("Burn Amount", Range(0.0, 1.0)) = 0.0// _LineWidth代表了周邊延申的效果線_LineWidth("Burn Line Width", Range(0.0, 10)) = 0.1_MainTex ("Base (RGB)", 2D) = "white" {}_BumpMap ("Normal Map", 2D) = "bump" {}_BurnFirstColor("Burn First Color", Color) = (1, 0, 0, 1)_BurnSecondColor("Burn Second Color", Color) = (1, 0, 0, 1)_BurnMap("Burn Map", 2D) = "white"{}}SubShader{Tags { "RenderType"="Opaque" "Queue"="Geometry"}Pass {Tags { "LightMode"="ForwardBase" }// 不要剔除背面,不然裁剪面片時會發(fā)現沒有背面Cull OffCGPROGRAM#include "Lighting.cginc"#include "AutoLight.cginc"#pragma multi_compile_fwdbase#pragma vertex vert#pragma fragment fragfixed _BurnAmount;fixed _LineWidth;sampler2D _MainTex;sampler2D _BumpMap;fixed4 _BurnFirstColor;fixed4 _BurnSecondColor;sampler2D _BurnMap;float4 _MainTex_ST;float4 _BumpMap_ST;float4 _BurnMap_ST;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;float4 tangent : TANGENT;float4 texcoord : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float2 uvMainTex : TEXCOORD0;float2 uvBumpMap : TEXCOORD1;float2 uvBurnMap : TEXCOORD2;float3 lightDir : TEXCOORD3;float3 worldPos : TEXCOORD4;SHADOW_COORDS(5)};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uvMainTex = TRANSFORM_TEX(v.texcoord, _MainTex);o.uvBumpMap = TRANSFORM_TEX(v.texcoord, _BumpMap);o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);TANGENT_SPACE_ROTATION;o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;TRANSFER_SHADOW(o);return o;}fixed4 frag(v2f i) : SV_Target {// 對噪聲紋理進行采樣fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;// 根據_BurnAmount來clip像素,保留白色去除黑色clip(burn.r - _BurnAmount);float3 tangentLightDir = normalize(i.lightDir);fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uvBumpMap));fixed3 albedo = tex2D(_MainTex, i.uvMainTex).rgb;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));// 對裁剪掉的部分進行混合顏色渲染fixed t = 1 - smoothstep(0.0, _LineWidth, burn.r - _BurnAmount);// 這一部分渲染的顏色是根據smoothstep獲取的形狀渲染的,// 被裁剪部分=0,因此經過smoothstep后周邊模糊區(qū)域會保留,中心區(qū)域裁剪,渲染范圍是裁剪部分區(qū)域 + _LineWidth// 而越靠近裁剪部分的像素渲染越接近firstColorfixed3 burnColor = lerp(_BurnFirstColor, _BurnSecondColor, t);// 深化顏色,看起來亮一點burnColor = pow(burnColor, 5);UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);// 最終再混合光照和燃燒特效色fixed3 finalColor = lerp(ambient + diffuse * atten, burnColor, t * step(0.0001, _BurnAmount));return fixed4(finalColor, 1);}ENDCG}// Pass to render object as a shadow casterPass {Tags { "LightMode" = "ShadowCaster" }CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_shadowcaster#include "UnityCG.cginc"fixed _BurnAmount;sampler2D _BurnMap;float4 _BurnMap_ST;struct v2f {V2F_SHADOW_CASTER;float2 uvBurnMap : TEXCOORD1;};v2f vert(appdata_base v) {v2f o;TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);return o;}fixed4 frag(v2f i) : SV_Target {fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;// 對陰影也需要剔除clip(burn.r - _BurnAmount);SHADOW_CASTER_FRAGMENT(i)}ENDCG}}FallBack "Diffuse"
}
例如火焰焚毀效果
發(fā)現配合不同的噪聲貼圖可以實現很多有意思的效果,例如掃描線重建
或者這樣的沙化效果,總而言之只要是類似的隨時間漸變效果應當都是能夠使用噪聲貼圖實現的,只是需要充分發(fā)揮想象力
水波效果
在模擬實時水面的時候,我們往往也會使用噪聲紋理作為高度圖,不斷修改水面的法線方向,以模擬水不斷流動的效果。我們會使用和時間相關的變量來對噪聲紋理進行采樣,當得到法線信息后再進行正常的反射 + 折射運算,得到最終的水面波動效果
在之前我們寫過一個實現了菲涅爾反射的玻璃效果,現在我們想要實現水波,自然也要使用菲涅爾反射,此外為了實現水面的波動效果,我們可以用一張噪聲貼圖,并不斷進行偏移采樣來模擬水面的隨機波動。以實現波光粼粼的效果。
Shader "Custom/WaterWave_Copy"
{Properties{_Color ("Main Color", Color) = (1,1,1,1)_MainTex ("Base Tex", 2D) = "white" {}_WaveMap ("Wave Map",2D) = "bump"{}_Cubemap ("Environment Cubemap", Cube) = "_Skybox" {}_WaveXSpeed ("Wave Horizontal Speed", Range(-0.1, 0.1)) = 0.01_WaveYSpeed ("Wave Vertical Speed", Range(-0.1, 0.1)) = 0.01_Distortion ("Distortion", Range(0, 100)) = 10}SubShader{Tags { "Queue"="Transparent" "RenderType"="Opaque" }// 抓取不透明物體渲染后的緩存,并保存到_RefractionTex紋理中// 此處GrabPass在渲染水面紋理之前,因此抓取的是未渲染水面時的場景畫面GrabPass { "_RefractionTex" }Pass{Tags{ "LightMode"="ForwardBase" }CGPROGRAM#include "UnityCG.cginc"#include "Lighting.cginc"#pragma multi_compile_fwdbase#pragma vertex vert#pragma fragment fragfixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;sampler2D _WaveMap;float4 _WaveMap_ST;samplerCUBE _Cubemap;fixed _WaveXSpeed;fixed _WaveYSpeed;float _Distortion; sampler2D _RefractionTex;float4 _RefractionTex_TexelSize;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;float4 tangent : TANGENT; float4 texcoord : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float4 scrPos : TEXCOORD0;float4 uv : TEXCOORD1;float4 TtoW0 : TEXCOORD2; float4 TtoW1 : TEXCOORD3; float4 TtoW2 : TEXCOORD4; };v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.scrPos = ComputeGrabScreenPos(o.pos);o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);o.uv.zw = TRANSFORM_TEX(v.texcoord, _WaveMap);// 用于計算光照模型(菲涅爾反射)。需要用到世界空間下的切線方向float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x); o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y); o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z); return o;}fixed4 frag(v2f i) : SV_Target {float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));// 計算水波紋理在uv上的采樣速度float2 speed = _Time.y * float2(_WaveXSpeed, _WaveYSpeed);// 對法線紋理采樣并將法線紋理轉換回切線空間// 此處為了模擬水波的不規(guī)則運動,bump1邊對speed正方向采樣,bump2對負方向采樣,并將兩種法線紋理采樣都應用上去fixed3 bump1 = UnpackNormal(tex2D(_WaveMap, i.uv.zw + speed)).rgb;fixed3 bump2 = UnpackNormal(tex2D(_WaveMap, i.uv.zw - speed)).rgb;fixed3 bump = normalize(bump1 + bump2);// 將場景的像素與法線進行混合以實現水面波動和場景畫面的顏色值的混合// _Distortion越大,水體背后的物體看起來變形程度越大float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;// 對z坐標進行相乘,以模擬深度越大,折射程度越大的效果i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;fixed3 refrCol = tex2D( _RefractionTex, i.scrPos.xy/i.scrPos.w).rgb;// 將采樣法線貼圖計算的切線空間坐標變換到世界空間下bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));// 采樣主紋理并計算菲涅爾反射fixed4 texColor = tex2D(_MainTex, i.uv.xy + speed);fixed3 reflDir = reflect(-viewDir, bump);fixed3 reflCol = texCUBE(_Cubemap, reflDir).rgb * texColor.rgb * _Color.rgb;fixed fresnel = pow(1 - saturate(dot(viewDir, bump)), 4);fixed3 finalColor = lerp(refrCol,reflCol,fresnel);//fixed3 finalColor = reflCol * fresnel + refrCol * (1 - fresnel);return fixed4(finalColor, 1);}ENDCG}}// 不投射陰影FallBack Off
}
全局霧效
從代碼上看來其實就是對原來的霧效后處理進行了一個噪聲紋理貼圖的采樣。
此處就不展開了