您需要 登录 才可以下载或查看,没有账号?注册
x
本帖最后由 Thepoly 于 2023-6-21 17:46 编辑
Hello . 大家好
今天给大家带来序列帧(纹理动画)实现 我是Thepoly
什么是序列帧
序列帧动画的原理非常简单,它像放电影一样,依次播放一系列关键帧图像,当播放速度达到一定数值时,看起来就是一个连续的动画。它的优点在于灵活性很强,我们不需要进行任何物理计算就可以得到非常细腻的动画效果。而它的缺点也很明显,由于序列帧中每张关键帧图像都不一样,因此,要制作一张出色的序列帧纹理所需要的美术工程量也比较大。 序列帧原理
将UV水平与垂直分成若干等份,依据时间进行横向和纵向的偏移
实现
首先将水平和垂直的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 -
|