UnityShader 序列帧动画Shader实现

如果游戏中,需要大量2D怪物,类似roguelike,割草的效果,就会有很多不同的帧动画,使用Animation,性能问题就很大,这个时候我们就需要使用gpu渲染,既能减少动画组件,还有效合批,再加上使用GPUInstance,轻松达到几千个怪物。另外这是一个序列帧动作,如果有多个角色动作,可以使用Texture2DArray,shader中的类型是2DArray。如有不对的地方,请指正。

本篇文章是一片转载文章,记录一下,通过学习文章的思路,自己放到项目使用,所以文章的代码没有测试,大家可以试试。

这一节介绍了 如何修改UV产生位移动画。

我们也可以通过修改UV产生序列帧播放。

使用数字来代表每个动画的位置

UV坐标分布为

数字增长方式 U是从左到右,V是从上倒下。

改下图片

使用一个符合UV增长方式的排列。

接下来使用上面的图片来制作Shader

需要添加3个参数来控制显示范围。

_X_Sum("序列水平个数",float) = 3
_Y_Sum("序列竖直个数",float) = 3
_ShowID("当前显示ID",float) = 0

首先需要吧_ShowID 的一个数据转换为二维坐标

首先获得V的坐标系数据

//对ID取模约束数值在0~最大图像之间。
_ShowID = _ShowID % (_X_Sum*_Y_Sum);

//显示ID默认是浮点数,向下取整获得整数
_ShowID = floor(_ShowID);

// 纵横向ID = 显示ID除以横向个数,使用Floor获取整数部分,就是纵向坐标
float indexY = floor(_ShowID / _X_Sum);

//横向ID = 整数ID减去 横向个数乘以纵向ID
float indexX = _ShowID - _X_Sum * indexY;

接下来吧0~1的原始UV约束进一个数字上 使用AnimUV记录

//依据个数缩小UV(放大图像)
float2 AnimUV = float2(i.uv.x / _X_Sum, i.uv.y / _Y_Sum);

获得默认位置显示“0”

添加左右横向偏移

//依据横向ID与横向个数获取偏移值累加给基础位置
AnimUV.x += indexX / _X_Sum ;

累加结果

添加上下纵向偏移

//(由下向上播放)  Y累加变大 
AnimUV.y +=indexY / _YSum;

一般这样就可以直接使用新的 AnimUV 获取图像了。

但是很多软件自动生成序列是这样的。

//(由下向上播放)  Y累加变大 
AnimUV.y +=indexY / _YSum;

改为

//(由上向下播放 )  纵向偏移 =  纵向总数-1(获得正确的ID区间上限0~2) - 当前ID(获得反向纵向ID),ID越大,Y越小 。
AnimUV.y +=(_Y_Sum-1 - indexY )/ _Y_Sum;

带入刚才的计算

最后获得贴图

//用新UV坐标获取贴图
fixed4 col = tex2D(_MainTex, AnimUV);

--------------"_Time"是Shader内置时间变量-----------

_Time.x(0.05倍速)

_Time.y(正常速度)

_Time.z(2倍速)

_Time.w(3倍速)

Shader源码

Shader "CRLuo/CRLuo_Teaching14_Tex_Amin_G"
{
    Properties
    {
		[NoScaleOffset]
        _MainTex ("Texture", 2D) = "white" {}
        _X_Sum("序列水平个数",float) = 3
		_Y_Sum("序列竖直个数",float) = 3
        _ShowID("当前显示ID",float) = 0
		 [Toggle(_AutoPlay_Key)] _AutoPlay_Key("自动播放",Float) = 0
		_PlaySpeed("播放速度",float) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog
			#pragma shader_feature  _AutoPlay_Key
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
			float  _X_Sum;
			float	_Y_Sum;
			float	_ShowID;
			float _PlaySpeed;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {

				//自动动画播放
			#ifdef  _AutoPlay_Key
             //当前ID累加 ,流逝时间(1秒)*播放速度(帧速率)
				_ShowID += _Time.y*	_PlaySpeed;

	         #endif



            //对ID取模约束数值在0~最大图像之间。
			_ShowID = _ShowID % (_X_Sum*_Y_Sum);

			//ID向下取整
			_ShowID = floor(_ShowID);

		  // 纵横向ID = ID除以横向个数,使用Floor获取整数部分,就是横向坐标
			float indexY = floor(_ShowID / _X_Sum);

			//横向ID = 整数ID减去 横向个数乘以纵向ID
                       float indexX = _ShowID - _X_Sum * indexY;

			//依据个数缩小UV(放大图像)
			float2 AnimUV = float2(i.uv.x / _X_Sum, i.uv.y / _Y_Sum);

			//依据横向ID与横向个数获取偏移值累加给基础位置
			AnimUV.x += indexX / _X_Sum ;

			//(由下向上播放)  如果纵向ID为0 ,Y累加变大 
			//AnimUV.y +=indexY / _YSum;

			//(由上向下播放 )  如果纵向ID为0  总数-1 - 当前ID,ID越大,Y越小 。
			AnimUV.y +=(_Y_Sum-1 - indexY )/ _Y_Sum;

			//用新UV显示贴图
			fixed4 col = tex2D(_MainTex, AnimUV);

			//透明剔除
			   clip(col.a - 0.5);
               
			   // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
               
				return col;
            }
            ENDCG
        }
    }
}

转载自UnityShader 基础(22)-UV坐标-序列帧动画 - 知乎

猜你喜欢

转载自blog.csdn.net/Ling_SevoL_Y/article/details/130881707