Unity 大地图高性能砍树顶点动画Shader


当前方案适合: 类饥荒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相关 就出来了哈

相关推荐
叶帆9 天前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
久数君9 天前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型
会思考的猴子10 天前
Unity VFX 属性 Postion 和 TargetPostion
unity
hai31524754310 天前
九章编程法 · 猜数字游戏 (GW-BASIC 重构版) *
人工智能·microsoft·游戏引擎·游戏程序
心前阳光10 天前
Unity资源导入之自动化资源导入
unity·自动化·游戏引擎
心前阳光10 天前
Unity之2021.3.45f2c1发布安卓程序遇到的问题
android·unity·游戏引擎
纪纯10 天前
PicoVR Unity Integration SDK 3.4 常用交互API
unity·游戏引擎·vr·pico
龙智DevSecOps解决方案10 天前
3A 游戏优化技术栈:如何打通引擎级分析工具与 DevOps 持续集成管线?
unity·性能优化·游戏开发·技术美术·perforce·unrealengine
葛兰岱尔10 天前
从 SolidWorks 到 Three.js,从 Inventor 到 Unity——制造业CAD模型“几何-语义一体化“转换,不再是天方夜谭!
开发语言·javascript·unity
鼎艺创新科技10 天前
三维电子沙盘中OSGB倾斜摄影数据的加载与渲染
游戏引擎·cocos2d