不知道是啥
0.本文示例代碼地址
1. Unity 內(nèi)置時間變量
動畫的本質(zhì)就是根據(jù)跟隨時間顯示不同畫面沛豌。我們要在 Shader 中來實現(xiàn)動畫,離不開時間變量的獲取赃额。目前 Unity Shader 提供了一系列內(nèi)置變量支持對于時間的訪問加派,所有與時間相關(guān)的內(nèi)置變量如下表:
Unity內(nèi)置時間變量
2. 序列幀動畫實現(xiàn)
2.1 Shader 中實現(xiàn)序列幀動畫的思路
在 Shader 中實現(xiàn)序列幀動畫,有以下幾個關(guān)鍵點:
- 所有的幀都繪制在同一張圖片上跳芳,作為紋理傳遞給 Shader芍锦,實際采樣時采樣大圖中對應的小圖部分
- 使用時間變量來計算當下應該展示的幀在紋理中的位置
- 在片元著色器中針對紋理采樣時,計算新的 uv 坐標
2.2 代碼分析
在場景中新建一個 Quad飞盆,面朝攝像機娄琉,然后創(chuàng)建shader和材質(zhì),并將材質(zhì)賦給 Quad吓歇。我們先貼最終代碼
Shader "Shader_Examples/07_SequenceAnim"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Speed ("Speed", Range(1, 100)) = 30
_RowCount ("Row Count", float) = 8
_ColumnCount ("Column Count", float) = 8
}
SubShader
{
Tags { "Queue"="Transparent" }
LOD 100
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _RowCount;
float _ColumnCount;
int _Speed;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float time = floor(_Time.y * _Speed);
float row = floor(time / _ColumnCount);
float column = time - row * _ColumnCount;
half2 uv = float2(i.uv.x /_ColumnCount, i.uv.y / _RowCount);
uv.x += column / _ColumnCount;
uv.y -= row / _RowCount;
fixed4 col = tex2D(_MainTex, uv);
return col;
}
ENDCG
}
}
}
- 變量聲明中使用
Speed
來控制序列幀動畫播放的速度 -
_RowCount
和_ColumnCount
聲明這大圖中小圖的排布方式 - 序列幀動畫一般都是包含透明度的圖片孽水,所以這里的 Shader 中需要渲染半透明物體的標配Tags
Tags { "Queue"="Transparent" }
以及半透明物體的渲染開關(guān)
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
- 頂點著色器沒有什么好說的,只干最簡單的事:將頂點坐標從模型坐標轉(zhuǎn)換到裁剪坐標
- 重點在片元著色器中城看,核心是如何計算當前應該渲染的小圖的實際 uv
float time = floor(_Time.y * _Speed);
float row = floor(time / _ColumnCount);
float column = time - row * _ColumnCount;
half2 uv = float2(i.uv.x /_ColumnCount, i.uv.y / _RowCount);
uv.x += column / _ColumnCount;
uv.y -= row / _RowCount;
2.3 最終渲染效果
序列幀動畫效果
3. 無限滾動背景
實現(xiàn)比較簡單女气,直接上 shader 代碼吧
Shader "Shader_Examples/07_ScrollingBackground"
{
Properties
{
_NearTex ("Near Texture", 2D) = "white" {}
_FarText ("Far Texture", 2D) = "white" {}
_Lightness ("Lightness", float) = 1.0
_SpeedNear ("Near Speed", Range(0, 1)) = 0.05
_SpeedFar ("Far Speed", Range(0, 1)) = 0.08
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _NearTex;
float4 _NearTex_ST;
sampler2D _FarText;
float4 _FarText_ST;
float _Lightness;
float _SpeedNear;
float _SpeedFar;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.uv, _NearTex) + frac(float2(_SpeedNear, 0.0) * _Time.y);
o.uv.zw = TRANSFORM_TEX(v.uv, _FarText) + frac(float2(_SpeedFar, 0.0) * _Time.y);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 nearColor = tex2D(_NearTex, i.uv.xy);
fixed4 farColor = tex2D(_FarText, i.uv.zw);
fixed4 color = lerp(nearColor, farColor, farColor.a);
color.rgb *= _Lightness;
return color;
}
ENDCG
}
}
}
幾個關(guān)鍵點:
- 用于無限循環(huán)的圖片,設置中的
WrapMode
必須設置為Repeat
测柠,如圖所示:
圖片的WrapMode設置 - 核心思想和 uv 動畫一樣炼鞠,根據(jù)時間變量對 uv 進行水平坐標的偏移,得到動畫效果
- 近層圖片和遠程圖片的速度不一樣
- 使用近層圖片的 alpha 值來對兩個圖片的顏色進行插值
-
可以把 uv 偏移值的計算放到 CPU 中計算轰胁,然后設置材質(zhì)參數(shù)谒主,可以得到完全一樣的效果
最終得到的動畫效果
滾動的雙層背景