【VRChat】PostProcessing の Bloom のかかり具合をスライダーで調整する

## 概要
- PostProcessing の Bloom のかかり具合をスライダーで調整できるよう
- Bloom のかかり具合は `Post-process Volume` の `weight` で調整できるが、スライダーで直接操作することはできない
- `Animator` で Bloom が ON 状態と OFF 状態を作成する
- そのフレームをスライダーで動かすことで Bloom のかかり具合を調整できる

## はじめに
私の作成したVRCWorld「[Music Stellar Lake](https://vrchat.com/home/launch?worldId=wrld_c330cf97-4ffb-40a9-b872-79a36905134d)」の公開に際して
ワールド内で使っているギミックの中から
特に汎用的なものをピックアップしていくつか紹介していこうと思っています

もし「役に立ったー！」となったらワールドに遊びに行ってもらえると
（ついでに #musicstellarlake のハッシュタグでツイートしてもらえると）
嬉しいです！


## 環境

- VRCSDK 3.0 2021.08.04.15.07
- Unity 2019.4.29f1
- Usharp v0.20.2

## 手順０：ポストプロセッシングを設定しブルームをかける
- こちらの記事を参考にポストプロセッシングの設定を行いBloomを導入してください（本題ではないため飛ばします）
    - [【VRChat】PostProcessingを使ってワールドをより良くする](https://qiita.com/sudare222/items/5be4b93de07dc3d7fd02)
- この時 **「最大ここまでかかってもよい」と思えるかかり具合で `Intensity` 等を設定してください**

## 手順１：ポストプロセッシングの `Animation` を設定する
注意： ここから先、`Post-process Volume` が紐づいている `GameObject` は `PPSv2` という名前で登場します

- `PPSv2` を選択
- `Add Component` から `Animator` を選択
- 上部のメニューから `Window` > `Animation` > `Animation` を選択

|Animationの選択|
|----|
|![animation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169868/f42bfe28-9171-a8c2-830b-ec80750529ed.png)|


- 表示されたウインドウの中央の `Create` をクリックして `.anim` ファイルを新規作成
    - この時、同じフォルダ内に `GameObject` の名前の `Animator` が生成される（今回の場合は「PPSv2」）

|Createをクリック|PPSv2アニメーター追加後の表示|
|----|----|
|![create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169868/548c2b7d-d70a-1fa5-4eeb-15793edf54ed.png)|![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169868/5ad2abc3-0d2a-25f2-7cce-d56eff526f5f.png)|

- `AddProperty` をクリックして PPSv2 の `Post Processing Volume.Weight` を選択
- カーソルを0フレームに合わせて「0」を入力
- カーソルを60フレームに合わせて「1」を入力
- ウィンドウ下方の `Curves` を選択
- 0フレームと60フレームが直線でつながるようにカーブを調整
    - この時 Shiftキー+マウスのホイールで縦方向（値方向）のズームインを行うと設定しやすい

|Dopesheet|Curves|
|----|-----|
|![animationclip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169868/da1ad0a4-f985-0865-80c4-5aa79a396d6a.png)|![ka-bu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169868/858a91db-d0f6-c9bd-5b8d-db7df277ab89.png)|

## 手順２：Animator の設定を行う
- 上部メニューから `Window` > `Animation` > `Animator` を選択
    - **`Animation` ではない**
- `Parameters` を選択し `+` から `Float` を追加し `MotionTime` とする
    - 初期値は0のままでOK
    - 状態が１つだけ存在するはずなので、`Motion Time` の `Parameters` チェックボックスをONに変えて `MotionTime` パラメーターを設定

|Animatorの設定|
|----|
|![animator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169868/f833f64f-bf57-133e-4e2c-06dc229438d9.png)|

## 手順３： `Animator` の `MotionTime` をスライダーで動かすための UdonSharp を書く
- `Project` ウィンドウの任意の場所で右クリックし、 `Create` > `U#Script` を選択し `PostProcessAnimatorController` という名前で保存
    - `UdonBehavior` コンポーネントからも生成できるが、このように生成すると任意の場所に任意の名前でスクリプトが作成できるためフォルダ構成がわかりやすくなる
- `PPSv2` の `Add Component` から　`UdonBehavior` を追加
- 先ほど生成された `PostProcessAnimatorController.asset`を `UdonBehavior` に設定
    - この時矢印下キーで選択すると **一番上のU#アセットが選択されてしまう** のでドラッグ＆ドロップで設定するのが確実
- `PostProcessAnimatorController.cs` ファイルをダブルクリックして開く
- 以下の通り書く


```cs:PostProcessAnimatorController.cs
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using UnityEngine.UI;

public class PostProcessAnimatorController : UdonSharpBehaviour
{

    [SerializeField] Slider slider;

    private Animator _animator;

    void Start()
    {

        _animator = this.gameObject.GetComponent<Animator>();
        _animator.SetFloat("MotionTime", 0.5f);
    }

    public void OnSliderValueChanged()
    {

        _animator.SetFloat("MotionTime", slider.value);
    }
}
```

### Udon 解説
- `[SerializeField]` をつけることで　`public` にすることなくインスペクタから `GameObject` 等の設定が可能
- `Start()` で `_animator` コンポーネントを取得
    - コンポーネントの取得は処理負荷がかかるためあらかじめ保存しておくと吉
- `public` で `OnSliderValueChanged()` メソッドを公開しておき、スライダーの値変化時に呼び出す
- 値が変化したらスライダーの値を `_animator` の `MotionTime` に設定するという流れ
- 真面目に実装するなら `_animator` の存在確認や `slider` の存在確認はした方がよいです


## 手順４：スライダーを設定する
- こちらの記事を参考にスライダーを追加する
    - [VRChatのワールドでuGUIを使う](https://qiita.com/gatosyocora/items/cc13445bfb18d55077c4)
        - SDK2 の記事ですがスライダーを追加するまでの部分は参考になるかと思います
            - 特に **`VRC_UiShape` コンポーネントをつける** 部分
- スライダーの各値を以下の通り設定
    - `Min Value` : 0
    - `Max Value` : 1
    - `Value` : 0.5
- スライダーの `OnValueChanged` の `+` ボタンをクリック
- スライダーの`OnValueChanged` に `PPSv2` を追加
    - ドラッグ＆ドロップで追加可能
- `Runtime Only` の横のドロップダウンリストをクリックして呼び出すメソッドとして `UdonBehavior` > `SendCustomEvent` を選択
- 呼び出す `UdonBehavior` のメソッド名を指定できるため、 `OnSliderValueChanged` を選択

|`Slider`　の `OnValueChanged` がこうなってたらOK|
|------|
|![slider.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169868/e6f7dc6a-f658-a34d-6c6b-deafa2d09ae8.png)|

**完成!!!!!!!!!!!!!!!!!**

## 【参考】なんでこんなめんどくさいことをする必要があるのか
- スライダーの値を直接 `weight` や `Intensity` に設定することができない
    - スクリプトを使って設定する必要がある
- `UdonSharp` は現状 `Bloom` をサポートしていない
    - `Intensity.value` を直接弄ることができない
- 同様に`PostProcessVolume` をサポートしていない
    - `weight` を直接弄ることができない
- アニメーションに変化を割り当てることで `weight` であれば動かすことができるので、これを利用する

**直線的に変化するアニメーションを作成してフレームを移動させることで、Udon で直接触れないパラメータを操作することができる**

この記事の肝心な部分はここに尽きると思います

## 終わりに


心地よい `Bloom` のかかり具合は人によって違うので
長時間居られるワールド作りをするなら結構役に立つのではないかと思います

いい記事だなーと思った方は是非「[Music Stellar Lake](https://vrchat.com/home/launch?worldId=wrld_c330cf97-4ffb-40a9-b872-79a36905134d)」をよろしくお願いします!!!!


## 参考ページ
- [VRChatのワールドでuGUIを使う](https://qiita.com/gatosyocora/items/cc13445bfb18d55077c4)
- [【VRChat】PostProcessingを使ってワールドをより良くする](https://qiita.com/sudare222/items/5be4b93de07dc3d7fd02)
- [Unity PostProcessing & Slider](https://www.reddit.com/r/VRchat/comments/mqmkzg/unity_postprocessing_slider/)