赞
踩
序列帧动画的原理是如此的简单,可以说只需要足够多张纸以及足够多的时间,就可以实现最简单的动画:
不使用 Animation 工具,只需要使用 Shader 中的内置时间变量,就可以实现最简单的序列帧动画了。就像最早的电影,依次展示一张又一张的图片,只要这些图片是连续的并且切换的足够快,那么当然就可以骗过人的眼睛,得到细腻的动画效果(现在我们的电脑电视本质上依然是这个原理,只不过是以帧的形式表现的)‘
序列帧的优点和缺点都很明显:
这是《Unity3D入门精要》中的一张例图,64张帧动画图像被合并在一张大的图像中,它们的大小相同,都为128 x 128,这些单张的图像有时也被叫做精灵(Sprite)
这也是 Unity3D 图集的处理方案
对于上面的图片,在 Shader 中只需要按照从左上到右下的顺序,依次截取一个个128 x 128的子区域作为当前要显示的纹理,就可以实现最简单帧序列动画了
在此之前,我们需要在 UnityShader 中获取当前场景运行的时间需要知道以下变量:
直接上代码,主要需要注意的有:
- Shader "Jaihk662/FrameAni1"
- {
- Properties
- {
- _Color("Color", Color) = (1, 1, 1, 1)
- _MainTex("Image Sequence", 2D) = "white" {}
- _HorizontalAmount("Horizontal Amount", Float) = 8 //对于样例中的图片,横纵需设为8,不要忘记
- _VerticalAmount("VerticalAmount", Float) = 8
- _Speed("Speed", Range(1, 100)) = 30
- }
- SubShader
- {
- LOD 200
- Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"} //当成半透明对象处理
- PASS
- {
- Tags { "LightMode" = "ForwardBase" }
- ZWrite Off
- Blend SrcAlpha OneMinusSrcAlpha
-
- CGPROGRAM
- #pragma vertex vert //声明顶点着色器的函数
- #pragma fragment frag //声明片段着色器的函数
- #include "UnityCG.cginc"
- #include "Lighting.cginc"
-
- fixed4 _Color;
- float _Speed;
- float _HorizontalAmount;
- float _VerticalAmount;
- sampler2D _MainTex;
-
- float4 _MainTex_ST;
- struct _2vert
- {
- float4 vertex: POSITION;
- float4 texcoord: TEXCOORD0;
- };
- struct vert2frag
- {
- float4 pos: SV_POSITION;
- float2 uv: TEXCOORD0;
- };
-
- vert2frag vert(_2vert v)
- {
- vert2frag o;
- o.pos = UnityObjectToClipPos(v.vertex);
- o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
- return o;
- }
- fixed4 frag(vert2frag i): SV_Target
- {
- float time = floor(_Time.y * _Speed);
- float row = floor(time / _HorizontalAmount);
- float column = time - row * _HorizontalAmount;
- row %= _VerticalAmount;
-
- half2 uv = i.uv + half2(column, _HorizontalAmount - row);
- uv.x /= _HorizontalAmount;
- uv.y /= _VerticalAmount;
-
- fixed4 color = tex2D(_MainTex, uv);
- color.rgb *= _Color;
- return color;
- }
- ENDCG
- }
- }
- FallBack "Transparent/VertexLit"
- }
可能结果看上去不是很好,这也是上面所说的缺点:为了保证动画流畅,只能牺牲画质
其实对于这样的火焰效果,一个主流的解决方案是使用粒子特效
UV 动画就是随时间不断改变纹理的 uv 坐标,以展现出“动态的”贴图
以下 Shader 可以实现滚动背景的效果,在没学 Shader 之前,背景的滚动都是通过修改其 transform 实现的
- Shader "Jaihk662/ScrollAni1"
- {
- Properties
- {
- _MainTex("Base Layer(RGBA)", 2D) = "white" {}
- _DetailTex("2nd Layer(RGBA)", 2D) = "white" {}
- _ScrollX("Base layer Scroll Speed", Float) = 1.0
- _Scroll2X("2nd layer Scroll Speed", Float) = 1.0
- _Multiplier("Layer Multiplier", Float) = 1
- }
- SubShader
- {
- LOD 200
- Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }
- PASS
- {
- Tags { "LightMode" = "ForwardBase" }
- ZWrite Off
- Blend SrcAlpha OneMinusSrcAlpha
-
- CGPROGRAM
- #pragma vertex vert //声明顶点着色器的函数
- #pragma fragment frag //声明片段着色器的函数
- #include "UnityCG.cginc"
- #include "Lighting.cginc"
-
- sampler2D _MainTex;
- sampler2D _DetailTex;
- float _ScrollX;
- float _Scroll2X;
- float _Multiplier;
-
- float4 _MainTex_ST;
- float4 _DetailTex_ST;
- struct _2vert
- {
- float4 vertex: POSITION;
- float4 texcoord: TEXCOORD0;
- };
- struct vert2frag
- {
- float4 pos: SV_POSITION;
- float4 uv: TEXCOORD0;
- };
-
- vert2frag vert(_2vert v)
- {
- vert2frag o;
- o.pos = UnityObjectToClipPos(v.vertex);
- o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0) * _Time.y); //frac(): 仅保留小数部分
- o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0) * _Time.y);
- return o;
- }
- fixed4 frag(vert2frag i): SV_Target
- {
- fixed4 firstLayer = tex2D(_MainTex, i.uv.xy);
- fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw);
-
- fixed4 color = lerp(firstLayer, secondLayer, secondLayer.a) * _Multiplier;
- return color;
- }
- ENDCG
- }
- }
- FallBack "VertexLit"
- }
参考资料:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。