简介:
在游戏中,如果遇到了类似旗子飘动的动画,可以使用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。