找回密码
 立即注册
查看: 192|回复: 0

《Unity Shader入门精要》笔记(十六)

[复制链接]
发表于 2022-8-3 18:57 | 显示全部楼层 |阅读模式
本文为《Unity Shader入门精要》第十一章《让画面动起来》的前两节内容《纹理动画》。
本文相关代码,详见:
原书代码,详见原作者github:
<hr/>1. Unity Shader中的内置变量(时间篇)

名称类型描述
_Timefloat4t是来自该场景加载开始所经过的时间,4个分量的值分别是(t/20, t, 2t, 3t)
_SimTimefloat4t是时间的正弦值,4个分量的值分别是(t/8, t/4, t/2, t)
_CosTimefloat4t是时间的余弦值,4个分量的值分别是(t/8, t/4, t/2, t)
unity_DeltaTimefloat4dt是时间增量,4个分量的值分别是(dt, 1/dt, smoothDt, 1/smoothDt)
2. 纹理动画

一般在各种资源都比较局限的移动平台上,往往会使用纹理动画来代替复杂的粒子系统等模拟各种动画效果。
2.1 序列帧动画

序列帧动画:一系列关键帧图像按一定速度依次播放,形成一个连续的动画。

  • 优点
灵活性强,无需任何物理计算,可得到非常细腻的动画效果。

  • 缺点
关键帧图像制作工作量较大。
接下来通过案例来了解序列帧动画的实现。
1)准备工作

完成如下准备工作:

  • 新建名为Scene_11_2_1的场景,并去掉天空盒;
  • 新建名为ImageSequenceAnimationMat的材质;
  • 新建名为Chapter11-ImageSequenceAnimation的Unity Shader,并赋给上一步创建的材质;
  • 在场景中新建一个四边形(Quad),调整它的位置,使其正对相机,并将第2步创建的 材质赋给它;
  • 保存场景。
2)编写Shader代码

打开Chapter11-ImageSequenceAnimation的Unity Shader,编写如下代码:
Shader "Unlit/Chapter 11/Image Sequence Animation"
{
    Properties
    {
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        // 关键帧图集
        _MainTex ("Image Sequence", 2D) = "white" {}
        // 图集横向关键帧数量
        _HorizontalAmount ("Horizontal Amount", Float) = 4
        // 图集纵向关键帧数量
        _VerticalAmount ("Vertical Amount", Float) = 4
        // 控制序列帧动画的播放速度
        _Speed ("Speed", Range(1, 100)) = 30
    }
    SubShader
    {
        // 序列帧通常是透明纹理,需要设置透明队列
        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"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

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

            half4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _HorizontalAmount;
            float _VerticalAmount;
            float _Speed;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                // _Time.y自场景加载后经过的时间
                float time = floor(_Time.y * _Speed);
                float row = floor(time / _HorizontalAmount);
                float column = time - row * _VerticalAmount;

                //half2 uv = float2(i.uv.x / _HorizontalAmount, i.uv.y / _VerticalAmount);
                //uv.x += column / _HorizontalAmount;
                //uv.y -= row / _VerticalAmount;

                half2 uv = i.uv + half2(column, -row);
                uv.x /= _HorizontalAmount;
                uv.y /= _VerticalAmount;

                fixed4 c = tex2D(_MainTex, uv);
                c.rgb *= _Color;

                return c;


                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }

    Fallback "Transparent/VertexLit"
}
3)配置材质面板

导入原书的图集纹理(见工程:Assets/Textures/Chap11/boom.png):


在纹理的Inspector窗口中勾选Alpha Is Transparency


Apply后将纹理拖到材质的Image Sequence属性,将Horizontal AmountVertical Amount属性分别设置为8:


4)最终效果

配置材质后,运行场景,得到最终效果如下:


2.2 滚动的背景

一些2D纸片游戏,会通过多层图片不同移动速度来实现类似景深、层次感的效果。接下来通过案例实现类似的效果。
1)准备工作

完成如下准备工作:

  • 新建名为Scene_11_2_2的场景,去掉天空盒,同时将相机的投影模式设置为正交投影
  • 新建名为ScrollingBackgroundMat的材质;
  • 新建名为Chapter11-ScrollingBackground的Unity Shader,并赋给上一步创建的材质;
  • 在场景中创建一个四边形(Quad),调整其位置、大小,使它充满相机的视野范围,并将第2步创建的材质赋给它;
  • 保存场景。
2)编写Shader代码

打开Chapter11-ScrollingBackgroundUnity Shader,编写如下代码:
Shader "Unlit/Chapter 11/Scrolling Background"
{
    Properties
    {
        // 第一层(较远)的背景纹理
        _MainTex ("Base Layer (RGB)", 2D) = "white" {}
        // 第二层(较近)的背景纹理
        _DetailTex("2nd Layer (RGB)", 2D) = "white" {}
        // 第一层背景纹理的水平滚动速度
        _ScrollX ("Base Layer Scroll Speed", Float) = 1.0
        // 第二层背景纹理的水平滚动速度
        _Scroll2X ("2nd Layer Scroll Speed", Float) = 1.0
        // 控制纹理的整体亮度
        _Multiplier ("Layer Multiplier", Float) = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                // uv使用float4类型,存储两张纹理的采样
                float4 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _DetailTex;
            float4 _DetailTex_ST;
            float _ScrollX;
            float _Scroll2X;
            float _Multiplier;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                // frac内置函数:返回数值的小数部分
                o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0) * _Time.y);
                o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0) * _Time.y);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed4 firstLayer = tex2D(_MainTex, i.uv.xy);
                fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw);

                // 根据第二层纹理的透明度值,得到两层颜色的叠一起后的颜色
                fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a);
                c.rgb *= _Multiplier;

                return c;
            }
            ENDCG
        }
    }

    Fallback "VertexLit"
}
3)配置材质面板

导入两张背景纹理(资源来自OpenGameArt:http://opengalart.org):




将两张纹理分别拖到Base Layer (RGB)2nd Layer (RGB)属性上,将远近纹理的水平移动速度分别调整为0.1和0.2:


4)最终效果

配置材质后,运行场景,得到最终效果如下:


以上是本次笔记的所有内容,下一次我们将学习《顶点动画》的相关知识。
<hr/>写在最后

本文内容会同步发在笔者的公众号上,欢迎大家关注交流!
公众号:程序员叨叨叨(ID:i_coder

本帖子中包含更多资源

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

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-24 10:52 , Processed in 0.113440 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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