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。

猜你喜欢

转载自blog.csdn.net/mango9126/article/details/80482365