【Unity(C#)】トンネルフェードでVRの酔いを軽減する

　　
　　
　　

この記事は

**『プログラミング完全未経験からUnityでの開発現場に迎え入れてもらえた世界一の幸せ者』**

の記事です。そのつもりでお読みください。
　　

##VRの酔い
私自身も毎日デバッグをしてて思うことですが、
**VRは本当に酔いやすい**です。(個人差はあります)

VR空間内と現実のプレイヤーの体に対するフィードバックが
異なる場合に引き起こりやすいです。


顕著な例を挙げると、ジェットコースターやドライブシミュレータなどです。

[VR空間内]・・・自らの体が移動しているように感じる
[現実]・・・何のフィードバックも受けていない(慣性力を受けていない)

この矛盾が酔いを引き起こします。


##トンネルフェード
酔いを軽減する方法の一つに、視野を狭くする方法があります。[[参考]](https://www.moguravr.com/vr-yoi-combated/)

それが**トンネルフェード**です。(勝手に名付けた)

酔いを軽減しながらちょっとした移動をさせたい場合(自動で移動、回転)に、使えます。

![GifCapture-201902100228289347.gif](https://qiita-image-store.s3.amazonaws.com/0/244071/b0b7fac1-0c6e-15cd-e5ec-4785dd5c5b0e.gif)


##PostProcessing
UnityのPackageで`PostProcessing`をImportすれば、
このトンネルフェードを簡単に再現できます。

`Window`→`Package Manager`に進みます。
![window_PackageManager.png](https://qiita-image-store.s3.amazonaws.com/0/244071/6fc00106-814a-8405-6295-a1c4b32267c7.png)


`PostProcessing`を`Install`です。
![PostProcessing.png](https://qiita-image-store.s3.amazonaws.com/0/244071/0c1c4ac5-c03d-7aac-cb26-b69c78369fce.png)


##設定
カメラに`PostProcessLayer`と`PostProcessVolume`をAdd Componetします。
`PostProcessLayer`の方で警告マークが出ているので、警告通りレイヤーを設定します。
**カメラのレイヤーと合わせる**必要があります。


`PostProcessVolume`の方では、ひとまず`Profile`の横のNewを押します。
![PostProcessingComponent.png](https://qiita-image-store.s3.amazonaws.com/0/244071/538b140e-6eb8-5fe0-2b4d-6dd177e6a5d0.png)

`Profile`の設定が完了したら、
`Add effect`→`unity`→`Vignette`の順に進みます。
その後↓の画像のように設定します。
![PostProcessing設定後.png](https://qiita-image-store.s3.amazonaws.com/0/244071/da702fc2-564e-39db-7089-48e03465e541.png)


ゲームビューでは多少大げさなぐらいに感じますが、
VRのHMDを通して見た場合(VIVEしか試してませんが...)はこれぐらいがちょうどいいです。
![トンネル　大げさ.png](https://qiita-image-store.s3.amazonaws.com/0/244071/4b9a7ac5-fa39-0aec-3781-f7b2df9c43d1.png)

`PostProcessVolume`の`weight`のスライダーを動かすと、画面が変わります。

##TunnelComponent
けっこう使うので、コンポーネントとして何回でも使いまわせるようにしました。


トンネルの色や、大きさを変えた場合に確認しやすいように、
キーボードの`Space`でトンネル開始、`BackSpace`でトンネル解除を可能にしてます。

name spaceに**using UnityEngine.Rendering.PostProcessing;**を入れてください
※私が試みた際には、何度かこのname spaceが参照できないとかなんとか言われて非常に困りました。
　原因不明です、再起動とかいろいろしたら直りました、わかる方いたら教えてください。

```C#

//CameraにAdd

    PostProcessVolume processVolume;

    Coroutine coroutine;

    [SerializeField]
    [Range(0.01f, 0.05f)]
    float tunnelSpeed = 0.01f;


    void Start()
    {
        processVolume = this.gameObject.GetComponent<PostProcessVolume>();
    }

    void Update()
    {
        //キー押してない間はreturn
        if (Input.anyKey == false)
        {
            return;
        }

        if(coroutine == null)
        {
            //テスト用　トンネル開始
            if (Input.GetKeyDown(KeyCode.Space) && processVolume.weight == 0)
            {
                coroutine = StartCoroutine(Tunnel_ON_Coroutine());
            }

            //テスト用　トンネル解除
            if (Input.GetKeyDown(KeyCode.Backspace) && processVolume.weight == 1)
            {
                coroutine = StartCoroutine(Tunnel_OFF_Coroutine());
            }

        }

    }

    //トンネル開始
    public void Tunnel_ON()
    {
        if(processVolume.weight == 0)
        {
            coroutine = StartCoroutine(Tunnel_ON_Coroutine());
        }
       
    }

    //トンネル解除
    public void Tunnel_OFF()
    {
        if (processVolume.weight == 1)
        {
            coroutine = StartCoroutine(Tunnel_OFF_Coroutine());
        }
            
    }


    IEnumerator Tunnel_ON_Coroutine()
    {
        while (processVolume.weight < 1)
        {
            yield return new WaitForSeconds(tunnelSpeed);
            processVolume.weight += 0.01f;
        }

        processVolume.weight = 1;
        StopCoroutine(coroutine);
        coroutine = null;
    }

    IEnumerator Tunnel_OFF_Coroutine()
    {
        while (processVolume.weight > 0)
        {
            yield return new WaitForSeconds(tunnelSpeed);
            processVolume.weight -= 0.01f;
        }

        processVolume.weight = 0;
        StopCoroutine(coroutine);
        coroutine = null;
    }
}
```


下記のメソッドをトンネルフェード、オン、オフしたい箇所で呼び出せばOKのはずです。(もう眠たいので試してません)

```C#
 //トンネル開始
    public void Tunnel_ON()
    {
        if(processVolume.weight == 0)
        {
            coroutine = StartCoroutine(Tunnel_ON_Coroutine());
        }
       
    }

    //トンネル解除
    public void Tunnel_OFF()
    {
        if (processVolume.weight == 1)
        {
            coroutine = StartCoroutine(Tunnel_OFF_Coroutine());
        }
            
    }
```

家にVIVEほしい。切実に。