
当前方案适合: 类饥荒2d生存类 大量的树动画
前言
在大地图中 成千上万的树 不可能给每一个树都用Spine来做,所以本文章分享了一种通过shader来实现的方案
在一些大的开放世界中会用 静态模型LOD+shader+动态替换被砍的那棵树来做动画 但是今天我们只讲在移动端如何去处理 大量的数
脚本中我用了MaterialPropertyBlock处理 不会打断合批 同时还能修改单个对象的属性
csharp
using UnityEngine;
[DisallowMultipleComponent]
public class TreeHitFx : MonoBehaviour
{
static readonly int ID_HitTime = Shader.PropertyToID( "_HitTime" );
static readonly int ID_HitAmp = Shader.PropertyToID( "_HitAmp" );
const float FORCE = 3f;
SpriteRenderer sr;
MaterialPropertyBlock mpb;
private Vector3 CachePos = Vector3.zero;
public void Init( Vector3 Pos, SpriteRenderer icon )
{
CachePos = Pos;
sr = icon;
mpb = new MaterialPropertyBlock( );
Clear( );
}
public void Clear( )
{
if ( null != mpb )
{
sr.GetPropertyBlock( mpb );
mpb.SetFloat( ID_HitTime, 0f );
mpb.SetFloat( ID_HitAmp, 0f );
sr.SetPropertyBlock( mpb );
}
}
/// <summary>
/// 播放受击动画
/// </summary>
/// <param name="worldHitPos">砍中点 (世界坐标)</param>
public void PlayHit( Vector2 worldHitPos )
{
sr.GetPropertyBlock( mpb );
mpb.SetFloat( ID_HitTime, Time.time );
mpb.SetFloat( ID_HitAmp, worldHitPos.x - CachePos.x > 0f ? FORCE : -FORCE );
sr.SetPropertyBlock( mpb );
}
}
c
Shader "Custom/Sprite_TreeHit"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
_HitTime ("Hit Time", Float) = -100
_HitAmp ("Hit Amplitude", Float) = 0.5
_HitFreq ("Hit Frequency", Float) = 15
_HitDamp ("Hit Damping", Float) = 3
_FlashColor ("Flash Color", Color) = (1,1,1,1)
_FlashDuration ("Flash Duration", Float) = 0.1
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ PIXELSNAP_ON
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
fixed flashFactor : TEXCOORD1;
};
fixed4 _Color;
float _HitTime;
float _HitAmp;
float _HitFreq;
float _HitDamp;
fixed4 _FlashColor;
float _FlashDuration;
v2f vert(appdata_t IN)
{
v2f OUT;
float t = _Time.y - _HitTime;
float isValidTime = step(0, t) * step(t, 5.0);
float decay = exp(-t * _HitDamp);
float wave = decay * sin(t * _HitFreq);
float bend = wave * _HitAmp * IN.texcoord.y * IN.texcoord.y * isValidTime;
IN.vertex.x += bend;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
float flashProgress = t / _FlashDuration;
OUT.flashFactor = saturate(1.0 - flashProgress) * step(0, t);
#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap (OUT.vertex);
#endif
return OUT;
}
sampler2D _MainTex;
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
c.rgb *= c.a;
c.rgb += _FlashColor.rgb * IN.flashFactor * c.a;
return c;
}
ENDCG
}
}
}
补充
关于这个树是如何通过定点来实现摇摆动画的, 其实很多文章都有哈, 原理和草是一样的, 鄙人有一点懒就不赘述了 如果想学习原理的 可以查一下类似 草shader相关 就出来了哈