1. 程式人生 > >Shader頂點偏移通道實現旗幟飄動效果

Shader頂點偏移通道實現旗幟飄動效果

簡介:

    在遊戲中,如果遇到了類似旗子飄動的動畫,可以使用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。