序列帧(纹理动画)实现
Thepoly原创 39721 0
实名

通过了实名认证的内容创造者

发布于 2023-6-21 17:45:08

您需要 登录 才可以下载或查看,没有账号?注册

x
本帖最后由 Thepoly 于 2023-6-21 17:46 编辑

Hello . 大家好
今天给大家带来序列帧(纹理动画)实现
我是Thepoly




什么是序列帧

序列帧动画的原理非常简单,它像放电影一样,依次播放一系列关键帧图像,当播放速度达到一定数值时,看起来就是一个连续的动画。它的优点在于灵活性很强,我们不需要进行任何物理计算就可以得到非常细腻的动画效果。而它的缺点也很明显,由于序列帧中每张关键帧图像都不一样,因此,要制作一张出色的序列帧纹理所需要的美术工程量也比较大。
序列帧原理
将UV水平与垂直分成若干等份,依据时间进行横向和纵向的偏移

cf00c57ba55dbba5c753d82aadcff84c.png

实现

0423b834dfbf9af3445e86403ea3c6d4.png


首先将水平和垂直的UV缩放到对应的块
这时候会发现UV显示的位置并不是1,而是7,因为UV是从左下角开始算的,U方向没问题,但是V方向会存在问题。
将UV向上偏移,偏移的像素距离为每个等距乘竖直方向的数量减一。此时,我们就将初始点控制在起始位置了。我们将时间取整后除水平和垂直,分别求得xy方向的偏移值增加一个frac函数,将值永远固定到一个范围内循环,否则在手机平台上,随着时间的精度越来越大,会出现锯齿状。URP下的序列帧完整代码

Shader "Custom/Flipbook"{    Properties    {        _BaseColor ("Base Color", color) = (1, 1, 1, 1)        _BaseMap ("BaseMap", 2D) = "white" { }        // _Sequence ("Sequence", vector) = (3, 3, 0, 0)        _HorizontalAmount ("Horizontal Amount", Float) = 3        _VerticalAmount ("Vertical Amount", Float) = 3        _Speed ("Speed", float) = 1    }
    SubShader    {        Tags { "Queue" = "Geometry" "RenderType" = "Opaque" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline" }        LOD 100
        Pass        {            Name "Unlit"            HLSLPROGRAM
            #pragma vertex vert            #pragma fragment frag            #pragma multi_compile_fog            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            struct Attributes            {                float4 positionOS : POSITION;                float2 uv : TEXCOORD0;            };
            struct Varyings            {                float4 positionCS : SV_POSITION;                float2 uv : TEXCOORD0;                float fogCoord : TEXCOORD1;            };
            CBUFFER_START(UnityPerMaterial)                half4 _BaseColor;                float4 _BaseMap_ST;                // float4 _Sequence;                float _HorizontalAmount;                float _VerticalAmount;                float _Speed;            CBUFFER_END            TEXTURE2D(_BaseMap);SAMPLER(sampler_BaseMap);            // #define smp _linear_clampU_mirrorV            // SAMPLER(smp);
            Varyings vert(Attributes v)            {                Varyings o = (Varyings)0;
                o.positionCS = TransformObjectToHClip(v.positionOS.xyz);                float Columns = v.uv.x / _HorizontalAmount;                float Rows = v.uv.y / _VerticalAmount;                Rows += (+1 / _VerticalAmount * (_VerticalAmount - 1));                o.uv = float2(Columns, Rows);                float SpeedTime = _Time.y * _Speed;                o.uv.x += frac(floor(SpeedTime) / _HorizontalAmount);                o.uv.y -= frac(floor(SpeedTime / _HorizontalAmount) / _VerticalAmount);                o.fogCoord = ComputeFogFactor(o.positionCS.z);                return o;            }            half4 frag(Varyings i) : SV_Target            {                half4 c;
                                half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv);                c = baseMap * _BaseColor;                c.rgb = MixFog(c.rgb, i.fogCoord);                return c ;            }            ENDHLSL
        }    }}BuildIn下可定义初始图的序列帧

Shader "Custom/Flipbook"{ Properties {  _Color ("Color", Color) = (1, 1, 1, 1)  _MainTex ("MainTex", 2D) = "white" { }  _Columns ("Columns", int) = 2  _Rows ("Rows", int) = 3  _Speed ("Speed", float) = 1  _StartFrame ("Start Frame", int) = 0 }  SubShader {      Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
  CGINCLUDE  #pragma target 2.0  ENDCG
  Blend SrcAlpha OneMinusSrcAlpha  AlphaToMask Off  Cull Back  ColorMask RGBA  ZWrite Off  ZTest LEqual        Pass  {   Name "Unlit"   Tags { "LightMode" = "ForwardBase" }   CGPROGRAM
   #pragma vertex vert   #pragma fragment frag   #pragma multi_compile_instancing
   #include "UnityCG.cginc"   #include "UnityShaderVariables.cginc"

   struct appdata   {    float4 vertex : POSITION;    float4 color : COLOR;    float2 uv : TEXCOORD0;    UNITY_VERTEX_INPUT_INSTANCE_ID   };      struct v2f   {    float4 vertex : SV_POSITION;    float2 uv : TEXCOORD1;    // float4 TSV : TEXCOORD0;    UNITY_VERTEX_INPUT_INSTANCE_ID    UNITY_VERTEX_OUTPUT_STEREO   };
   uniform half4 _Color;   uniform sampler2D _MainTex;   uniform int _Columns;   uniform int _Rows;   uniform half _Speed;   uniform int _StartFrame;
      v2f vert(appdata v)   {    v2f o;    UNITY_SETUP_INSTANCE_ID(v);    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);    UNITY_TRANSFER_INSTANCE_ID(v, o);    // *** BEGIN Flipbook UV Animation vars ***    // 计算出所有的块    float AllTiles = _Columns * _Rows;    float ColumnsOffset = 1.0f / _Columns;    float RowsOffset = 1.0f / _Rows;    float SpeedTime = _Time.y * _Speed;    //将UV等分,得到当前的Tiling的位置。    float2 StartFrame = float2(ColumnsOffset, RowsOffset);    //用当前的速度+上希望的当前帧除以所有图取余数四舍五入,判断是否小于零,确定当前的图块索引    float CurrentTileIndex = round(fmod(SpeedTime + _StartFrame, AllTiles));    CurrentTileIndex += (CurrentTileIndex < 0) ? AllTiles : 0;    //用当前图块的索引除横向的方块,再乘以偏移值。    float indexU = round(fmod(CurrentTileIndex, _Columns));    float OffsetX = indexU * ColumnsOffset;
    float indexV = round(fmod((CurrentTileIndex - indexU) / _Columns, _Rows));    // 反转 Y 从上到下得到Tiling    indexV = floor(_Rows - 1) - indexV;    float OffsetY = indexV * RowsOffset;    // o.TSV.x = fmod(3, 3);    o.uv = v.uv * StartFrame + float2(OffsetX, OffsetY);    o.vertex = UnityObjectToClipPos(v.vertex);    return o;   }      fixed4 frag(v2f i) : SV_Target   {    UNITY_SETUP_INSTANCE_ID(i);    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);    fixed4 finalColor;    finalColor = _Color * tex2D(_MainTex, i.uv);    // return float4(i.TSV.x, i.TSV.x, i.TSV.x, 1.);    return finalColor;   }   ENDCG
  } }}

- End -


评分

参与人数 3元素币 +22 活跃度 +10 展开 理由
龙哥Longer... + 8 + 4 留下了没有技术含量的口水
rainreborn + 7 + 3 楼主有心了
wwwxajhcom + 7 + 3 看看东西好不好

查看全部评分

还没有设置签名!您可以在此展示你的链接,或者个人主页!
使用道具 <
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表