|
本文为《Unity Shader入门精要》第十一章《让画面动起来》的前两节内容《纹理动画》。 本文相关代码,详见:
原书代码,详见原作者github:
<hr/>1. Unity Shader中的内置变量(时间篇)
名称 | 类型 | 描述 | _Time | float4 | t是来自该场景加载开始所经过的时间,4个分量的值分别是(t/20, t, 2t, 3t) | _SimTime | float4 | t是时间的正弦值,4个分量的值分别是(t/8, t/4, t/2, t) | _CosTime | float4 | t是时间的余弦值,4个分量的值分别是(t/8, t/4, t/2, t) | unity_DeltaTime | float4 | dt是时间增量,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 &#34;Unlit/Chapter 11/Image Sequence Animation&#34;
{
Properties
{
_Color (&#34;Color Tint&#34;, Color) = (1, 1, 1, 1)
// 关键帧图集
_MainTex (&#34;Image Sequence&#34;, 2D) = &#34;white&#34; {}
// 图集横向关键帧数量
_HorizontalAmount (&#34;Horizontal Amount&#34;, Float) = 4
// 图集纵向关键帧数量
_VerticalAmount (&#34;Vertical Amount&#34;, Float) = 4
// 控制序列帧动画的播放速度
_Speed (&#34;Speed&#34;, Range(1, 100)) = 30
}
SubShader
{
// 序列帧通常是透明纹理,需要设置透明队列
Tags {
&#34;Queue&#34; = &#34;Transparent&#34;
&#34;IgnoreProjector&#34; = &#34;True&#34;
&#34;RenderType&#34;=&#34;Transparent&#34;
}
Pass
{
Tags {
&#34;LightMode&#34; = &#34;ForwardBase&#34;
}
// 关闭深度写入
ZWrite Off
// 设置混合模式
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include &#34;UnityCG.cginc&#34;
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 &#34;Transparent/VertexLit&#34;
}
3)配置材质面板
导入原书的图集纹理(见工程:Assets/Textures/Chap11/boom.png):
在纹理的Inspector窗口中勾选Alpha Is Transparency:
Apply后将纹理拖到材质的Image Sequence属性,将Horizontal Amount和Vertical Amount属性分别设置为8:
4)最终效果
配置材质后,运行场景,得到最终效果如下:
2.2 滚动的背景
一些2D纸片游戏,会通过多层图片不同移动速度来实现类似景深、层次感的效果。接下来通过案例实现类似的效果。
1)准备工作
完成如下准备工作:
- 新建名为Scene_11_2_2的场景,去掉天空盒,同时将相机的投影模式设置为正交投影;
- 新建名为ScrollingBackgroundMat的材质;
- 新建名为Chapter11-ScrollingBackground的Unity Shader,并赋给上一步创建的材质;
- 在场景中创建一个四边形(Quad),调整其位置、大小,使它充满相机的视野范围,并将第2步创建的材质赋给它;
- 保存场景。
2)编写Shader代码
打开Chapter11-ScrollingBackgroundUnity Shader,编写如下代码:
Shader &#34;Unlit/Chapter 11/Scrolling Background&#34;
{
Properties
{
// 第一层(较远)的背景纹理
_MainTex (&#34;Base Layer (RGB)&#34;, 2D) = &#34;white&#34; {}
// 第二层(较近)的背景纹理
_DetailTex(&#34;2nd Layer (RGB)&#34;, 2D) = &#34;white&#34; {}
// 第一层背景纹理的水平滚动速度
_ScrollX (&#34;Base Layer Scroll Speed&#34;, Float) = 1.0
// 第二层背景纹理的水平滚动速度
_Scroll2X (&#34;2nd Layer Scroll Speed&#34;, Float) = 1.0
// 控制纹理的整体亮度
_Multiplier (&#34;Layer Multiplier&#34;, Float) = 1.0
}
SubShader
{
Tags { &#34;RenderType&#34;=&#34;Opaque&#34; }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include &#34;UnityCG.cginc&#34;
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 &#34;VertexLit&#34;
}
3)配置材质面板
导入两张背景纹理(资源来自OpenGameArt:http://opengalart.org):
将两张纹理分别拖到Base Layer (RGB)和2nd Layer (RGB)属性上,将远近纹理的水平移动速度分别调整为0.1和0.2:
4)最终效果
配置材质后,运行场景,得到最终效果如下:
以上是本次笔记的所有内容,下一次我们将学习《顶点动画》的相关知识。
<hr/>写在最后
本文内容会同步发在笔者的公众号上,欢迎大家关注交流!
公众号:程序员叨叨叨(ID:i_coder) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|