当前位置:   article > 正文

UnityShader22:序列帧动画

序列帧动画

 

一、序列帧动画

序列帧动画的原理是如此的简单,可以说只需要足够多张纸以及足够多的时间,就可以实现最简单的动画:

不使用 Animation 工具,只需要使用 Shader 中的内置时间变量,就可以实现最简单的序列帧动画了。就像最早的电影,依次展示一张又一张的图片,只要这些图片是连续的并且切换的足够快,那么当然就可以骗过人的眼睛,得到细腻的动画效果(现在我们的电脑电视本质上依然是这个原理,只不过是以帧的形式表现的)‘

序列帧的优点和缺点都很明显:

  • 优点:无需任何计算,直接显示图片,逻辑简单,不用怎么考虑性能
  • 缺点:制作非常耗时,需要给出 N 张图片,并且为了不占太多的空间往往单张图片分辨率都很低

这是《Unity3D入门精要》中的一张例图,64张帧动画图像被合并在一张大的图像中,它们的大小相同,都为128 x 128,这些单张的图像有时也被叫做精灵(Sprite)

这也是 Unity3D 图集的处理方案

 

二、Unity内置时间变量

对于上面的图片,在 Shader 中只需要按照从左上到右下的顺序,依次截取一个个128 x 128的子区域作为当前要显示的纹理,就可以实现最简单帧序列动画了

在此之前,我们需要在 UnityShader 中获取当前场景运行的时间需要知道以下变量:

  • _Time:float4(t/20, t, 2t, 3t):其中 t 为自当前场景加载开始所经过的时间
  • _SinTime:float4(t/8, t/4, t/2, t):其中 t 为自当前场景加载开始所经过的时间的正弦值
  • _CosTime:float4(t/8, t/4, t/2, t):其中 t 为自当前场景加载开始所经过的时间的正弦值
  • unity_DeltaTime:float(dt, l/dt, smoothDt, 1/smoothDt):其中 dt 为时间增量,smoothDt 为平滑处理后的时间增量

 

三、简单的爆炸效果

直接上代码,主要需要注意的有:

  • 需要当作半透明对象处理,并且对于纹理,需要勾选 Alpha Is Transparency 属性
  • 核心在于片段着色器,根据上一节的内置时间变量推算当前应该截取64块区域中的哪一块,并且得出正确的 uv,采样

  1. Shader "Jaihk662/FrameAni1"
  2. {
  3. Properties
  4. {
  5. _Color("Color", Color) = (1, 1, 1, 1)
  6. _MainTex("Image Sequence", 2D) = "white" {}
  7. _HorizontalAmount("Horizontal Amount", Float) = 8 //对于样例中的图片,横纵需设为8,不要忘记
  8. _VerticalAmount("VerticalAmount", Float) = 8
  9. _Speed("Speed", Range(1, 100)) = 30
  10. }
  11. SubShader
  12. {
  13. LOD 200
  14. Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"} //当成半透明对象处理
  15. PASS
  16. {
  17. Tags { "LightMode" = "ForwardBase" }
  18. ZWrite Off
  19. Blend SrcAlpha OneMinusSrcAlpha
  20. CGPROGRAM
  21. #pragma vertex vert //声明顶点着色器的函数
  22. #pragma fragment frag //声明片段着色器的函数
  23. #include "UnityCG.cginc"
  24. #include "Lighting.cginc"
  25. fixed4 _Color;
  26. float _Speed;
  27. float _HorizontalAmount;
  28. float _VerticalAmount;
  29. sampler2D _MainTex;
  30. float4 _MainTex_ST;
  31. struct _2vert
  32. {
  33. float4 vertex: POSITION;
  34. float4 texcoord: TEXCOORD0;
  35. };
  36. struct vert2frag
  37. {
  38. float4 pos: SV_POSITION;
  39. float2 uv: TEXCOORD0;
  40. };
  41. vert2frag vert(_2vert v)
  42. {
  43. vert2frag o;
  44. o.pos = UnityObjectToClipPos(v.vertex);
  45. o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
  46. return o;
  47. }
  48. fixed4 frag(vert2frag i): SV_Target
  49. {
  50. float time = floor(_Time.y * _Speed);
  51. float row = floor(time / _HorizontalAmount);
  52. float column = time - row * _HorizontalAmount;
  53. row %= _VerticalAmount;
  54. half2 uv = i.uv + half2(column, _HorizontalAmount - row);
  55. uv.x /= _HorizontalAmount;
  56. uv.y /= _VerticalAmount;
  57. fixed4 color = tex2D(_MainTex, uv);
  58. color.rgb *= _Color;
  59. return color;
  60. }
  61. ENDCG
  62. }
  63. }
  64. FallBack "Transparent/VertexLit"
  65. }

可能结果看上去不是很好,这也是上面所说的缺点:为了保证动画流畅,只能牺牲画质

其实对于这样的火焰效果,一个主流的解决方案是使用粒子特效

 

四、UV动画

UV 动画就是随时间不断改变纹理的 uv 坐标,以展现出“动态的”贴图

以下 Shader 可以实现滚动背景的效果,在没学 Shader 之前,背景的滚动都是通过修改其 transform 实现的

  1. Shader "Jaihk662/ScrollAni1"
  2. {
  3. Properties
  4. {
  5. _MainTex("Base Layer(RGBA)", 2D) = "white" {}
  6. _DetailTex("2nd Layer(RGBA)", 2D) = "white" {}
  7. _ScrollX("Base layer Scroll Speed", Float) = 1.0
  8. _Scroll2X("2nd layer Scroll Speed", Float) = 1.0
  9. _Multiplier("Layer Multiplier", Float) = 1
  10. }
  11. SubShader
  12. {
  13. LOD 200
  14. Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }
  15. PASS
  16. {
  17. Tags { "LightMode" = "ForwardBase" }
  18. ZWrite Off
  19. Blend SrcAlpha OneMinusSrcAlpha
  20. CGPROGRAM
  21. #pragma vertex vert //声明顶点着色器的函数
  22. #pragma fragment frag //声明片段着色器的函数
  23. #include "UnityCG.cginc"
  24. #include "Lighting.cginc"
  25. sampler2D _MainTex;
  26. sampler2D _DetailTex;
  27. float _ScrollX;
  28. float _Scroll2X;
  29. float _Multiplier;
  30. float4 _MainTex_ST;
  31. float4 _DetailTex_ST;
  32. struct _2vert
  33. {
  34. float4 vertex: POSITION;
  35. float4 texcoord: TEXCOORD0;
  36. };
  37. struct vert2frag
  38. {
  39. float4 pos: SV_POSITION;
  40. float4 uv: TEXCOORD0;
  41. };
  42. vert2frag vert(_2vert v)
  43. {
  44. vert2frag o;
  45. o.pos = UnityObjectToClipPos(v.vertex);
  46. o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0) * _Time.y); //frac(): 仅保留小数部分
  47. o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0) * _Time.y);
  48. return o;
  49. }
  50. fixed4 frag(vert2frag i): SV_Target
  51. {
  52. fixed4 firstLayer = tex2D(_MainTex, i.uv.xy);
  53. fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw);
  54. fixed4 color = lerp(firstLayer, secondLayer, secondLayer.a) * _Multiplier;
  55. return color;
  56. }
  57. ENDCG
  58. }
  59. }
  60. FallBack "VertexLit"
  61. }

 

参考资料:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/138278
推荐阅读
相关标签
  

闽ICP备14008679号