Shader頂點偏移通道實現旗幟飄動效果
阿新 • • 發佈:2019-01-09
簡介:
在遊戲中,如果遇到了類似旗子飄動的動畫,可以使用Shader來簡單實現,搞了個Shader,把原理和演算法簡單寫了下注釋,大家如果需要加上貼圖,調整下引數就可以直接用。
/************************************************************************ * File : FlagsFluttering * Author : Mango * Time : 2018-5-28 * UnityVer.: 2017.1.0f3 * Description: 實現旗子飄動效果(向前及陰影渲染) ************************************************************************ */ Shader "Shader/FlagsFluttering" { Properties{ //旗子紋理 _Texture("Texture", 2D) = "white" {} //旗子飄動振幅(y軸) _Magnitude("Magnitude", Range(0, 10)) = 1 //旗子飄動速度 _Speed("Speed", Range(0, 10)) = 3 } SubShader{ Tags{ "RenderType" = "Opaque" } Pass{ Name "FORWARD" Tags{ "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #define UNITY_PASS_FORWARDBASE #include "UnityCG.cginc" #pragma multi_compile_fwdbase_fullshadows #pragma multi_compile_fog #pragma only_renderers d3d9 d3d11 glcore gles #pragma target 3.0 uniform sampler2D _Texture; uniform float4 _Texture_ST; uniform float _Magnitude; uniform float _Speed; struct VertexInput { float4 vertex : POSITION; float2 texcoord0 : TEXCOORD0; }; struct VertexOutput { float4 pos : SV_POSITION; float2 uv0 : TEXCOORD0; float4 posWorld : TEXCOORD1; UNITY_FOG_COORDS(2) }; //旗子飄動,演算法是根據當前旗子貼圖上所有頂點,根據時間的正弦值做週期運動 VertexOutput vert(VertexInput v) { VertexOutput o = (VertexOutput)0; o.uv0 = v.texcoord0; //獲取當前物體的世界座標,用於在移動旗子的時候,旗子的頂點移動會相對此時的物體,避免移動過程中出現不再飄動 float4 objPos = mul(unity_ObjectToWorld, float4(0,0,0,1)); float4 time = _Time; //頂點的座標計算,根據當前物體位置,計算出當前所有頂點的位置,然後根據時間關係計算正弦值 v.vertex.xyz += (sin((((mul(unity_ObjectToWorld, v.vertex).r - objPos.r) + (mul(unity_ObjectToWorld, v.vertex).b - objPos.b)) + (time.g*_Speed)))*float3(0,1,0)*_Magnitude*o.uv0.r); o.posWorld = mul(unity_ObjectToWorld, v.vertex); o.pos = UnityObjectToClipPos(v.vertex); UNITY_TRANSFER_FOG(o,o.pos); return o; } //最終貼圖顯示 float4 frag(VertexOutput i) : COLOR{ float4 objPos = mul(unity_ObjectToWorld, float4(0,0,0,1)); float4 _Texture_var = tex2D(_Texture,TRANSFORM_TEX(i.uv0, _Texture)); float3 finalColor = _Texture_var.rgb; fixed4 finalRGBA = fixed4(finalColor,1); UNITY_APPLY_FOG(i.fogCoord, finalRGBA); return finalRGBA; } ENDCG } Pass{ Name "ShadowCaster" Tags{ "LightMode" = "ShadowCaster" } Offset 1, 1 Cull Back CGPROGRAM #pragma vertex vert #pragma fragment frag #define UNITY_PASS_SHADOWCASTER #include "UnityCG.cginc" #include "Lighting.cginc" #pragma fragmentoption ARB_precision_hint_fastest #pragma multi_compile_shadowcaster #pragma multi_compile_fog #pragma only_renderers d3d9 d3d11 glcore gles #pragma target 3.0 uniform float _Magnitude; uniform float _Speed; struct VertexInput { float4 vertex : POSITION; float2 texcoord0 : TEXCOORD0; }; struct VertexOutput { V2F_SHADOW_CASTER; float2 uv0 : TEXCOORD1; float4 posWorld : TEXCOORD2; }; VertexOutput vert(VertexInput v) { VertexOutput o = (VertexOutput)0; o.uv0 = v.texcoord0; float4 objPos = mul(unity_ObjectToWorld, float4(0,0,0,1)); float4 time = _Time; v.vertex.xyz += (sin((((mul(unity_ObjectToWorld, v.vertex).r - objPos.r) + (mul(unity_ObjectToWorld, v.vertex).b - objPos.b)) + (time.g*_Speed)))*float3(0,1,0)*_Magnitude*o.uv0.r); o.posWorld = mul(unity_ObjectToWorld, v.vertex); o.pos = UnityObjectToClipPos(v.vertex); TRANSFER_SHADOW_CASTER(o) return o; } float4 frag(VertexOutput i) : COLOR{ float4 objPos = mul(unity_ObjectToWorld, float4(0,0,0,1)); SHADOW_CASTER_FRAGMENT(i) } ENDCG } } //注意回滾Shader FallBack "Diffuse" }
再給大家推薦一個Shader的視覺化編輯外掛——Shader Forge,類似PlayerMaker,使用多個節點,根據相應的演算法進行計算組合就可以實現簡單的Shader。