序列帧动画

游戏画面中之所以能产生动态效果主要的原因是因为 游戏循环 机制,即游戏画面每隔一个固定时间(每一帧)就会重新渲染。游戏运行时,每一帧都会更新屏幕,这种更新频率通常称为 帧率(Frames Per Second,FPS)比如 30 FPS、60 FPS 代表的就是 1秒钟更新30次,1秒钟更新60次

而之所以看起来画面是变化的,是因为我们在每一帧可能都会改变游戏中对象的位置、角度、缩放、颜色等等信息后重新渲染,一般情况下,只要帧率大于24FPS,人眼就认为一帧帧切换着的画面是流畅且连贯的了

利用Shader制作动态效果的关键就是 —— 利用时间变化来改变数据,从而导致渲染结果改变,带来画面变化

时间是关键数据,Shader中提供了对应的内置时间变量

  • float4 _Time:4个分量的值分别是(t / 20, t, 2t, 3t),其中t代表该游戏场景从加载开始缩经过的时间
  • float4 _SinTime:4个分量的值分别是(t / 8, t / 4, t / 2, t), 其中t代表 游戏运行的时间的正弦值
  • float4 _CosTime:4个分量的值分别是(t / 8, t / 4, t / 2, t),其中t代表 游戏运行的时间的余弦值
  • float4 unity_DeltaTime:4个分量的值分别是(dt, 1 / dt, smoothDt, 1 / smoothDt),dt代表帧间隔时间(上一帧到当前帧间隔时间),smoothDt是平滑处理过的时间间隔,对帧间隔时间进行某种平滑算法处理后的结果

一般会利用时间和什么数据一起计算,来达到动态效果呢?

  • 颜色:通过时间控制颜色的变化,比如 渐变、闪烁 等效果
  • 位置:利用时间使顶点在某个方向上移动,比如 波动 等效果
  • 纹理坐标:利用时间变化来动态改变纹理坐标,比如 水流、云彩、序列帧动画 等效果
  • 法线:利用时间动态修改法线方向,比如 风吹草动 等效果
  • 缩放:利用时间改变物体缩放比例,比如 脉动、跳动等效果
  • 透明度:利用时间控制物体透明度,比如 淡入淡出、闪烁等效果

1、序列帧动画原理

关键点:

  • UV坐标范围0~1,原点为图片左下角;
  • 图集序列帧动画播放顺序为从左到右,从上到下

分析问题

  • 如何得到当前应该播放哪一帧动画?
  • 如何将采样规则从0~1修改为在指定范围内采样?

问题解决思路

  • 用内置时间参数 _Time.y 参与计算得到具体哪一帧

时间是不停增长的数值,用它对总帧数取余,便可以循环获取到当前帧数

  • 利用时间得到当前应该绘制哪一帧后

我们只需要确认从当前小图片中,采样开始位置,采样范围即可,采样开始位置,可以利用当前帧和行列一起计算,采样范围可以将0~1范围 缩放转换到 小图范围内

以下图为例

Shader "ShaderProj/8/SequentialFrameAnimation"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        // 图集行列 
        _Rows ("Rows", int) = 8
        _Columns ("Columns", int) = 8
        _Speed ("Speed", float) = 1
    }
    SubShader
    {
        // 因为背景是透明的,所以要以透明模式来渲染,并且关掉深度写入
        Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector" = "True" }

        Pass
        {
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"


            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Rows;
            float _Columns;
            float _Speed;

            v2f vert (appdata_base v)
            {
                v2f data;
                data.vertex = UnityObjectToClipPos(v.vertex);
                data.uv = v.texcoord;
                
                return data;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //得到当前帧 利用时间变量计算
                float frameIndex = floor(_Time.y * _Speed) % (_Rows * _Columns);
                //小格子(小图片)采样时的起始位置计算
                //除以对应的行和列 目的是将行列值 转换到 0~1的坐标范围内
                // 1 - (floor(frameIndex / _Columns) + 1)/_Rows
                // +1 是因为把格子左上角转换为格子左下角
                // 1- 因为UV坐标采样时从左下角进行采样的
                float2 frameUV = float2(frameIndex % _Columns / _Columns, 1 - (floor(frameIndex / _Columns) + 1) / _Rows);
                //得到uv缩放比例 相当于从0~1大图 隐射到一个 0~1/n的一个小图中
                float2 size = float2(1 / _Columns, 1 / _Rows);
                //计算最终的uv采样坐标信息
                //*size 相当于把0~1范围 缩放到了 0~1/8范围
                //+frameUV 相当于把起始的采样位置 移动到了 对应帧小格子的起始位置
                float2 uv = i.uv * size + frameUV;

                return tex2D(_MainTex, uv);
            }
            ENDCG
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值