[VFX Graph]音楽ライブにいる「サイリウム振ってる集団」をつくる

#目次
[1.はじめに](#1-はじめに)
[2.つくるもの](#2-つくるもの)
[3.VFXGraphとは](#3-VFXGraphとは)
[4.つくりかた](#4-つくりかた)
[5.完成品](#5-完成品)
[6.参考](#6-参考)

#1. はじめに
それはとある休日のこと。
わたしは「Unityでなんか作ってみるネタないかな」と思いながら、
[ユニティちゃん Candy Rock Star ライブステージ！](https://youtu.be/M_GUlXJ52YA?t=60)を眺めておりました。

そのときふいに思ったのです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/7f540e44-5f16-7a82-27fa-a68581652db5.png)

「ライブっぽいモーションなのに、観客いなくてかわいそう…」
と。
というわけで、VFX Graphを利用して
ユニティちゃんを囲む ~~オタク~~ サイリウム集団をつくってみます。

#2. つくるもの

先に作るもののイメージを見てもらいましょう。こんなのをつくります。

![ezgif-6-84f5e5c772cd.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/393cc39f-1afa-bd66-2a8c-33576c612617.gif)

ユニティちゃんの周りを取り囲む、サイリウム集団のエフェクトです。
UNITE IN THE SKYにあわせて棒を振ってます。たのしそう

![ezgif-6-0bda0b1acf9b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/1e9b76da-f10b-f065-7744-b9e064bdc1b8.gif)

アピったりもします。「ユニティちゃんこっちみて～」みたいな。
この2種類の動きを外部から切り替えられるようなサイリウム集団のエフェクトをこれからつくっていきます。

※ エフェクト以外のステージ、モデル、モーションは
[こちら](https://unity-chan.com/download/index.php)の「ユニティちゃんライブステージ！ -Candy Rock Star-」を利用しています。

#3. VFXGraphとは
[Visual Effect Graph](https://unity.com/ja/visual-effect-graph)
Unityの比較的新しめな機能の１つです。
「ノードベースのプログラミング環境を備えた高性能な GPU パーティクルエフェクトシステム」だそう。
ノードベースなのでわりと簡単にいろんなエフェクトが作れます。
基本的な使い方については[Unite Tokyo 2019 の公演](https://youtu.be/Xwmdl4sbsjY)が超わかりやすいです。
こいつを使ってエフェクトをつくっていきます。

#4. つくりかた

VFX Graphの初期状態はこちら
![gif_animation_011.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/9a108713-f603-e4e4-db1b-437fa7d1d558.gif)

初期グラフはこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/3c9b0390-f797-94a9-b67e-c6b883cdad74.png)

ここから以下の流れでエフェクトをつくります。

- サイリウム単体のパーティクルをつくる
- モーションを付ける
- サイリウム集団をステージ状に配置して色を付ける
- モーションを増やす

※ わりと細かく解説していくので、「細かいことは見ればわかる」「動くものが欲しい」という方は
「[5.完成品](#5-完成品)」までスキップしてください。

では、順にやっていきます。

## 環境

- Unity 2019.4.16f1
- Visual Effect Graph 7.3.1

## サイリウム単体のパーティクルをつくる

### テクスチャを貼り付けてみる
まずはサイリウムを用意しましょう。
![Psyllium_white_half.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/8d9702d6-b32b-a35a-f8a9-99b090fd79f1.png)
このpngを `Output Particle Quad` の `MainTexTure` に設定します。
下半分が空白になっているのは、後で行う回転処理を簡単にするためです。（後でもう一度解説します）
![gif_animation_012.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/43d12a46-19f8-7745-e327-729c364e331f.gif)

飛んで消えてくサイリウムができました

### 位置を固定する

つくりたいのは飛んで消えてくサイリウムではなく「その場で動き続けるサイリウム」です。
移動と消滅を防ぐために、`Output Particle Quad` の内部ブロックを全部消した上で
`Spawn`と`Initialize Particle`を変更します。
ついでに動きをわかりやすくするため、いったん1本だけのサイリウムにしてしまいましょう。
ブロックはこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/bd0f9ddb-d2e3-a070-5f30-739dcb65c24a.png)
ポイントは `Single Burst` ブロック。
こいつを使うことで、パーティクルの生成を1回だけにできます。
また、`Initialize Particle`の`Capacity` が「一度に存在する最大パーティクル数」なので、こいつを1にしてしまえばサイリウムは1本しか現れなくなります。

![gif_animation_014.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/2f63afca-a2d0-f74a-d68c-fa8e7fbc9a87.gif)
さみしいけど、まずはここから

## モーションを付ける
`Update Particle` にブロックを追加し、フレームごとに角度情報を更新して「棒を振る動き」を表現します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/16d7e144-0b9c-8b23-f02a-9a5cd3f055ea.png)
（角度ではなく角速度を与えたほうが自然な動きになりそうですが、調整が大変だったので今回は位置を直接与えます）
`Periodic Total Time`で棒を振る速度を、`Sample Curve`で動きの挙動を表現し、`Multiply`で棒を振る最大角度を設定します。
今回は「棒を振って戻す」動作を2拍で行うこととして、UNITE IN THE SKY(BPM140)およそ2拍分の時間である0.857(s)を設定しました。
ここの調整は基本的にアナログ作業です。いい感じのSample Curveを作りましょう。
また、ここで設定する回転角度は「パーティクルの中心が回転軸」となっています。
「下半分が空白となっているサイリウム画像」をパーティクルのテクスチャとして設定したのは、
この設定で回転軸がサイリウムの根本となるよう調整した結果なのでした。
![gif_animation_016.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/d39bd845-60ce-91b5-9c2d-516cffe60c4f.gif)
真正面から見るとぺこぺこしてるように見えますね。軸を固定しているので仕方ないです。
（今回は簡略化のため、回転軸の移動は行いませんでした。）

ここまでで基本となるサイリウムパーティクルの完成です。

## サイリウム集団をステージ状に配置して色を付ける

作ったサイリウムを増やして観客っぽいエフェクトをつくり、ユニティちゃんのステージを囲いましょう。

### サイリウムを増やす
まずは作ったサイリウムを増殖させましょう。
`Spawn`と`Initialize Particle`ブロックを再び変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/4ea04633-60b7-06ed-ba0f-f86edcb1f6da.png)

`Initialize Particle`は、「`Position`の範囲(`Kill`の範囲は除く)に、`Capatiy`個のパーティクルを生成する」という構造。
ユニティちゃんのステージを置く部分にサイリウムを生成したくなかったので、中心部分は球状に`kill`しています。
また、`Spawn`の`Periodic Burst`は、`Count`個のパーティクルを一瞬で生成してくれます。
![gif_animation_017.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/d5db0796-d935-9705-2282-8bab3d70b1c0.gif)

生成したパーティクルの注視点を一か所にあつめるため、`Output`に`LookAtPosition`を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/d482bd20-3c04-fb7e-3536-75d97f3586c7.png)
これで`0,0,0`にユニティちゃんがいれば、サイリウム集団は全員ユニティちゃんのほうを見て棒を振るという寸法です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/514134ef-af82-d081-8318-491ca5cc76a3.png)

角度を合わせてユニティちゃんを召喚してみると、だんだんそれっぽくなってきました。

### 色を付ける
サイリウムに色を付けます。`Update Particle`に`Set Color`ブロックを追加しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/7a3dc323-66e9-2c6d-88c3-a57fece97c62.png)
パーティクル単位でランダムなHSVを生成し、RGBに変換して`Set Color`につなぎます。
`Max`と`Min`でHの範囲を指定できます（今回は完全にランダム）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/9bc4615e-6a8e-6ac8-15a3-dcad1a831c48.png)
カラフルですね。
また、`Random Number` を削除すれば、単色のサイリウムになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/1b134af2-2805-4a7e-3ed5-8dfc6d210850.png)
UOっぽいものとかできます。

### 生成位置を調整する
ここまででエフェクトはほぼ完成したのですが、生成したパーティクルは平面上に配置されているので
あまり「たくさんいる」感じがしませんね。数のわりに見栄えがちょっとさみしいです。
それに奥のひとはユニティちゃんが見にくそうで、なんだかかわいそうな気がしてきました。
ということで、武道館のように「中心から離れたサイリウムほど高い位置にいる」ように生成位置を調整しましょう。
`Initialize Particle`に`Add Position`ブロックを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/6944053a-8043-e72a-3734-c94f44804e12.png)
沢山ブロックをつなげていますが、やっていることはシンプルで

```math
z = \sqrt{x^2 + y^2}
```
となるz座標の計算です。これでゆるやかな曲線を表現します。
各パーティクルの位置を`Get Attribute`で取得し、z座標を計算して格納することで
おおよそお椀型にサイリウムを生成できます。
`Negate`ブロックでお椀の向きを反転させ、最後の`Multiply`と`Add`で倍率を調整しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/bbce8502-c8d0-1d07-4b9f-d5e7d07950e5.png)

ちょっと見栄えが良くなっていませんか？

![gif_animation_021.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/5960464a-5738-efb9-7b78-ae815a567186.gif)
引きで見るとこんなかんじ。
これにユニティちゃんモデルとステージギミックを追加すれば、観客付きライブステージの完成です！

## モーションを増やす
最後にモーションを増やして、外部から切り替えられるようにしてみます。

### アピールモーションをつくる
サイリウム集団がユニティちゃんにアピールするモーションを作ってみます。
曲の最後なんかに「わーっ！」って騒いでるイメージのやつです。
エフェクトとノードをまとめて貼り付けてしまいます。
![gif_animation_022.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/68fb07eb-2332-add4-a7f7-1cce874237cf.gif)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/5a5c00b3-2aac-1009-b638-03c8815265dc.png)
回転軸がz軸であること以外は先に作った縦振りのモーションと基本的に同じですが、
`Periodic Total Time`をランダム化しているのがポイントです。
実際のライブなんかでも、アピールしているときの棒振り速度は人によって違いますよね？
これが全員同じ速度だと、なんだか気持ち悪い動きになってしまいます。
![gif_animation_023.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/92fbe23e-3933-0cb8-37ce-0bdd51e6668c.gif)
なんか変ですね…良い感じに速度がばらけるようランダム化しましょう。

### モーションを切り替える
作ったモーションは外部から切り替えられるようにしておくと、スクリプトやTimelineで変化させることができて便利です。
外部から切り替えられるように、`Switch`ブロックと`Blackbord`を利用した上で
2種類のモーションを同時に`Set Angle`へつないでおきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/d31c952e-07f1-a6f2-d6db-32d7738a07f6.png)
`Switch`ブロックは`Test Value`の値を確認し、0が入っていればValue0、1が入っていればValue1…といった具合に
出力を切り替えることが出来ます。
また、左の変数リストみたいなやつがBlackbordです。
ここには任意の値を格納したブロックを作成しておくことができ、そのまま変数ブロックとして利用できます。
加えて`Exposed`オプションを有効にしておけば、コンポーネントの`Properties`から値を取得したり変更したりすることが出来るようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/b4dba53c-6079-4662-00d8-ff5611345936.png)

今回は変数`PsyliumMotionSwitch`を作成し、その値が

- 0なら縦振り
- 1なら横振り（アピール）

のモーションとなるよう切り替えを行っています。
![gif_animation_031.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/cad16b64-8ff2-95be-99f4-4cfc8b982396.gif)
Timelineで値を切り替えてみた例(今回はTimelineの解説はしません)

#5. 完成品

**これにてエフェクト完成です！お疲れ様でした！**
最後に完成したノードグラフを見ておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84576/218ea938-a0a8-d7e5-0d18-f97d083c21e7.png)
モーションだけでなく、サイリウムの色も切り替えられるようにしてみました。（切り替えの仕組みは同じです）
また、私の手元で作成したエフェクトをpackage化して[github](https://github.com/semprecalando/unity/tree/master/PsyliumVFX)に置いておいたので
手っ取り早く使いたい方は試してみてください。
（動作保証はできませんのであしからず）

#6. 参考

[Visual Effect Graph(公式マニュアル)](https://docs.unity3d.com/Manual/com.unity.visualeffectgraph.html)
[パーティクルエフェクトが超進化する！ Visual Effect Graph の基礎と応用 - Unite Tokyo 2019](https://youtu.be/Xwmdl4sbsjY)
[UnityのVisual Effect Graphの設定と使い方](https://gametukurikata.com/effect/visualeffectgraph)

(シェーダが書ける方はこちらを参考にした方がいいかも↓)
[Unity でシェーダを使って 20,000 人が音楽に合わせてサイリウム振ってる様子を作ってみた](http://tips.hecomi.com/entry/2014/04/20/003058)