簡単な手書きエフェクトをUnityのTimelineを使って再生する

はじめに

簡単な手書きエフェクトを描いてUnityに持ち込んでみました。 その過程をメモしておきます。

Kritaで手書きエフェクトを描く

Kritaにはアニメーション機能が存在します。 その機能を使ってエフェクトを描きました。

Animation with Krita — Krita Manual version 4.1.7

作成したエフェクトを一枚のテクスチャに収めます。

今回は10コマでしたが、8コマや16コマ32コマなどの テクスチャサイズをきれいに割り切れるもののほうが素敵ですね。

Kritaのグリッド表示機能を使うと配置が楽になります。

Grids and Guides Docker — Krita Manual version 4.1.7

エフェクト用のメッシュをBlenderで作成する

エフェクト用にUVを開いた板ポリを用意しました。

単純な板ポリだけでなく立体的な形状とかにしてみるのも面白そうです。

UnityでUVをずらして表示するシェーダを作成する

作成したShaderは次のとおりです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Shader "Unlit/effect001"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Multiply ("Multiply", Float) = 10
_T ("T", Float) = 0
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
ZWrite Off
Cull Off
Blend SrcAlpha OneMinusSrcAlpha

Pass
{
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 _Multiply;
float _T;

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

// float t = _Time.y * 24;
float t = _T;
o.uv.y /= 10;
o.uv.y *= -1;
o.uv.y -= 0.1 * floor(t);

if (t < 0 || t >= 10) {
o.uv = 0;
}

return o;
}

float4 frag (v2f i) : SV_Target
{
float4 col = tex2D(_MainTex, i.uv);
col.rgb *= _Multiply;
return col;
}
ENDCG
}
}
}

_Tという値を渡していること、UVのy方向を1/10にしていること、 tfloorしている部分がポイントです。 floorによってコマ送りが表現できています。 _Multiplyは後のBloomで光らせるためにいれています。

マテリアルの_Tを操作するアニメーションクリップを作成する

エフェクト用メッシュをシーンに配置します。

先ほど作ったシェーダからエフェクト用のマテリアルを作成します。 マテリアルのテクスチャに作成したテクスチャを渡します。

マテリアルをエフェクト用メッシュに設定します。

エフェクト用メッシュを選択した状態で、アニメーションウィンドウからアニメーションを作成します。

マテリアルの_Tの値をアニメーションするプロパティとして登録します。

fpsを24にして、1フレームずつ-1から10までキーフレームを打ちます。

Timelineにアニメーションクリップを配置する

今回はエフェクトにTimeline機能を使ってみます。

新しくPlayable Directorと名付けた空のGameObjectを作成します。

Playable Directorを選択した状態でTimelineウィンドウのCreateボタンを押します。

作成するとPlayable Directorというコンポーネントと Animatorというコンポーネントが追加されます。

Animatorはいらないので削除します。

Playable DirectorのBindingsのAnitation Trackに エフェクト用メッシュのAnimatorを登録します。

アニメーションクリップをタイムラインに配置します。

タイムラインの長さを固定長にして2秒にしました。

エフェクト用メッシュのアニメーションはタイムラインでコントロールするので、 コントローラをNoneにします。

エフェクトをループ再生するためにPlayable DirectorのWrap ModeをLoopにします。

ここまでの作業で次のようになります。

Post ProcessingのBloomを適用する

「Window>Pcakage Manager」からPost Processingを入れます。

カメラにPost Processin Layerを追加し、LayerをPostProcessingに変更します。

新しいGameObjectを作成しLayerをPostProcessingにして、 Post Processing VolumeをアタッチしてBloomを設定します。

この作業でよい感じにエフェクトが光るようになります。

Cinemachineのカメラ揺れを入れる

Package ManagerからCinemachineをインストールします。

CameraにCinemachine Brainをアタッチします。

Virtual Cameraと名付けた空のGameObjectを配置します。

Cinemachine Virtual Cameraをアタッチします。 Noiseを加えることで手ブレを与えられます。

Add ExtensionからImpulse Listenerを追加します。 これで衝撃を受け取れるようになります。

Timelineから衝撃を発生させたいのですが、 Timeline上でのイベントはUnityのバージョン2019以降になるようです。 そのため、ここではアクティベーショントラックを利用して衝撃を発生させます。

空のオブジェクトを作成してImpulse Sourceと名付けます。

Cinemachine Impulse Sourceスクリプトをアタッチします。 このスクリプトのGenerateImpulse ()メソッドを呼ぶことで衝撃を発生させます。 activeをfalseにしておきます。

Impulse Sourceに次のスクリプトをアタッチします。

1
2
3
4
5
6
7
8
9
10
11
12
using System.Collections;
using System.Collections.Generic;
using Cinemachine;
using UnityEngine;

public class ImpulseSource : MonoBehaviour {

void OnEnable () {
GetComponent<CinemachineImpulseSource> ().GenerateImpulse ();
}

}

OnEnable()のタイミングで衝撃を発生させるスクリプトになります。

Timelineにアクティベーショントラックを追加します。

Impulse Sourceを登録します。

アクティベーショントラックはGameObjectのactiveを切り替えます。 衝撃を発生させたいタイミングでアクティブになるようにトラックを編集します。

これでTimelineの特定のタイミングでカメラを揺らせるようになりました。

おわりに

今回は単純な板ポリに手書きのエフェクトを貼り付けるだけでしたが、 もっと複雑なメッシュを利用したりパーティクルを組み合わせたりして 色々なエフェクトが作れそうですね。