このチャプターでは、SVG素材から作成したテクスチャ素材を利用して、以下のような線のアニメーションを作る方法を紹介します。
サンプルデータ
線のアニメーションのサンプルデータはGitHubにて公開中です
使用するツール
Adobe Illustrator 2020
素材の準備
まず最初に、SVGファイルから以下のようなグラデーション付きの素材を作成し、Unityへインポートします。
1. SVG素材のインポート (Illustrator)
SVGファイルをAdobe Illustratorにインポートします。
OKマークのSVGファイルは https://ikonate.com/ からお借りしました。
2. グラデーションをつける (Illustrator)
グラデーションパネルにて「パスに沿ってグラデーションを適用」を選択し、
パスに沿ったグラデーションを設定します。
Unity上では、黒い部分から白い部分へ向かって白塗りが流れていくようなアニメーションになります。
3. 素材のエクスポート (Illustrator)
アートボードの名前は 「ok-ring」としておきましょう。
ファイル -> 書き出し -> スクリーン用に書き出し から素材を書き出して、Unityへ持っていきます。
4. 素材のインポート (Unity)
ok-ringのテクスチャ設定にて、sRGBのチェックを外します。
テクスチャを表示してみる (Unity)
先ほど作成した、ok-ring.png
をShaderGraphで出力してみます。
以下のようなShaderGraphを組んでみてください。
結果
OKマークが表示されます。
アニメーション用ShaderGraphの作成
次にアニメーションを行うためののShaderGraphを作成します。
プロパティの作成
アニメーションの進行度を表すFloatプロパティ Progress を作成します。
Progress = 0 はアニメーションの最初、Progress = 1 はアニメーションの最後 といった意味の実数値です。
ShaderGraphの作成
StepやMultiplyノードを使って、以下のようなShaderGraphを組みます。
結果
マテリアル上でProgressの値を変化させると、以下のように線が削れていきます。
線が削れる表現としては良さそうなのですが、アルファの削り部分がところどころ汚くなってしまいます。
Smoothstepノードを利用したアニメーション
Stepの代わりにSmoothstepノードを利用することで、アルファを0から1へゆるやかに削ることができます。
結果
マテリアル上でProgress
の値を変化させると、ゆるやかに線が削れます。
削り部分の汚さは目立ちにくくなりました。
調整 : Progress = 1 でアルファを完全に削りきる
Smoothstepを利用した削り表現ですが、Progress
= 1にした場合にアルファが削りきれずに残ってしまっています。
Progress = 1 をアニメーションの終わりとして、アルファは完全に削れてくれた方が都合が良いです。
Progressの範囲変換
Progress =0, 1 でのアルファ値はグラフは以下のようになります。
アルファ値は黄色い線で表しています。
Progress = 0 の時はアルファは常に1ですが、Progress = 1 の時はアルファが削り切れずに残ってしまっています。
Remapを利用した範囲変換
ProgressにRemapノードを接続することで、Progressがとる数値の範囲を変換することができます。
結果
Progress = 1 の時にアルファが完全に削り切れています。
ShaderGraph全体
今回作ったShaderGraphは以下のようになっています。
おまけ : AnimationClipを使ってアニメーションさせる
UIマテリアルのパラメータは、AnimationClipを使ってアニメーションさせることができません。
C#スクリプトを利用したアニメーション
以下の方法を取ることで、AnimationClipから削りアニメーションをコントロールすることができます。
- C#スクリプト(コンポーネント)を利用して、マテリアルの
_Progress
プロパティを毎フレーム更新する - Animation Clipでコンポーネントのパラメータを変化させる
Materialのプロパティ_Progressを更新するC#スクリプト
以下のコンポーネントは、Image(RawImage)にアタッチされているマテリアルのプロパティ_Progress
を更新するスクリプトです。
namespace ShaderGraphCookBook
{
using UnityEngine;
using UnityEngine.UI;
[ExecuteAlways]
[RequireComponent(typeof(MaskableGraphic))]
public class UIMaterialProgress : MonoBehaviour
{
[SerializeField, Range(0f, 1f)] private float progress = 0f; // マテリアルに渡す_Progressの値
private Image _image = null;
private RawImage _rawImage = null;
private readonly int _progressId = Shader.PropertyToID("_Progress"); // シェーダープロパティのReference名
private void Start()
{
Initialize();
}
/// <summary>
/// 描画フレームで呼ばれる
/// </summary>
void Update()
{
var material = GetMaterial();
if (material != null)
{
// マテリアルのプロパティ _Progress を更新
material.SetFloat(_progressId, progress);
}
}
/// <summary>
/// 初期化処理
/// </summary>
void Initialize()
{
var component = GetComponent<MaskableGraphic>();
_image = component as Image;
_rawImage = component as RawImage;
}
/// <summary>
/// Imageにアタッチされているマテリアルの取得
/// </summary>
Material GetMaterial()
{
if (_image != null) return _image.material;
if (_rawImage != null) return _rawImage.material;
return null;
}
}
}
結果
Imageにアタッチして、コンポーネントのProgress
というスライダーを動かすとマテリアルの_Progress
も変化します。
AnimationClipを使ったアニメーション
AnimationClipからコンポーネントのProgress
を変化させると、UIがアニメーションします。