【Unity(C#)】SteamVR Pluginを使わないVRでのフェードアウト、フェードイン

　　
　　
　　
この記事は

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

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


##SteamVR Pluginを使う
[[SteamVR Pluginを使うフェード]](https://qiita.com/OKsaiyowa/items/201b6a0582934143e4c8)←こちらです。

##SteamVR Pluginを使わない
前回の記事を活かして作りました。→[3Dでのフェード](https://qiita.com/OKsaiyowa/items/474dc86173d74b49edfd)

他にもやり方はありますが、今回はVRのカメラとは別にサブカメラを用意する方法を書きます。

サブカメラにキャンバス(UI)のみ映る設定をします。
`Culling Mask`で`UI`以外のチェックをはずせばOKです。
`Culling Mask`は描画するオブジェクトをレイヤーごとに設定できる便利なプロパティーです。

つぎに、
**・サブカメラの描画順を最後(一番目に近い位置)にする**
**・背景が二つのカメラで描画される(片方のカメラに映る背景が片方のカメラの映像を塗りつぶす)ことを防ぐ**
上記2点を設定します。
![カメラの最強の絵.png](https://qiita-image-store.s3.amazonaws.com/0/244071/74d0373d-8b11-85b5-9a28-d24046163a9d.png)
このとても上手な絵を見れば一目瞭然だと思いますが、
メインカメラ、サブカメラで描画する順番があります。

私は最初聞いたとき`描画とか言われてもイメージしづらい`と感じました。
なので、絵のように物理的に距離があるものだと考えるようにしました。
**目に近い位置のもの(描画順が遅いもの)が一番手前に描画される**、といった理解の仕方です。

**※以後、描画順の違いに物理的な距離の違いがあるような説明をしますが
　そんなものはありませんのでご注意ください。ただのイメージです**

しかし、カメラの場合、目に近いほう(サブカメラ)にもメインカメラと同じ背景が映りこみます。
(`Culling Mask`で背景の描画は消せません)

それにより、サブカメラに映った背景が、メインカメラより目に近い位置で描画されるので
メインカメラの映像を上から塗りつぶしてしまいます。
~~(ここの説明はややこしいので声に出して5回くらい読んでください)~~

この塗りつぶしを防ぐために
`Clear Flags`を`Depth only`にします。
背景が上書きされることがなくなります。

ただし、`Depth`というパラメーターの確認をしてください。
数字の小さい順番で先に描画される(目から遠くなる)ので今回の場合は
メインカメラの方がサブカメラより`Depth`が小さくないといけません。
(おそらく勝手にそうなってます)

###最終的な設定画面
![CameraVRSetting.png](https://qiita-image-store.s3.amazonaws.com/0/244071/4e3b0159-b967-a90e-38e8-7f17d4aae0cc.png)
長々と説明しましたが、設定項目としてはこれだけです。


##コード
```C#
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class UtilityFadeCanvas : MonoBehavior
{
    Canvas faceCanvas;

    Image facePanel;

    Camera faceCamera;

    Coroutine coroutine;

    GameObject camera_G;

    [Tooltip("フェードする色")]
    public Color panelColor = new Color(0, 0, 0, 0);

    [Tooltip("フェードの時間")]
    public float fadeTime = 1;

    [Tooltip("0～1の値で透明度を設定")]
    public float alpha_Panel = 0.5f;

    const float FIXED_UPDATE_DELTATIME = 0.02f;

    float startTime;

    void Awake()
    {
        //シーンをロードするたびに新しいカメラを生成
        if (GameObject.Find("OnlyUIRenderingCamera"))
        {
            Destroy(GameObject.Find("OnlyUIRenderingCamera"));
        }
    }

    // Start is called before the first frame update
    void Start()
    {

        //カメラ自動生成
        camera_G = new GameObject("OnlyUIRenderingCamera");
        faceCamera = camera_G.AddComponent<Camera>();
        faceCamera.clearFlags = CameraClearFlags.Depth;
        faceCamera.cullingMask = (1 << LayerMask.NameToLayer("UI"));

        //キャンバス生成＆設定
        GameObject canvas_G = new GameObject("FaceCanvas");
        faceCanvas = canvas_G.AddComponent<Canvas>();
        canvas_G.AddComponent<CanvasRenderer>();


        //キャンバスのポジションを調整
        Vector3 canvasPosition = canvas_G.transform.position;
        canvasPosition.x = 0;
        canvasPosition.y = 0;
        canvasPosition.z = 0.1f;
        canvas_G.transform.localPosition = canvasPosition;

        //レンダリングをfaceCameraに
        faceCanvas.renderMode = RenderMode.ScreenSpaceCamera;
        faceCanvas.worldCamera = faceCamera;

        //パネル生成＆設定
        GameObject panel_G = new GameObject("FacePanel");
        facePanel = panel_G.AddComponent<Image>();

        Color tmpColor = facePanel.color;
        tmpColor.a = 0f;
        facePanel.color = tmpColor;

        //パネルをキャンバスの子に設定
        panel_G.transform.parent = canvas_G.transform;

        //パネルのポジションを正面に調整
        Vector3 panelPosition = panel_G.transform.localPosition;
        panelPosition.x = 0;
        panelPosition.y = 0;
        panelPosition.z = 0;
        panel_G.transform.localPosition = panelPosition;


        //キャンバスをカメラの子に設定
        canvas_G.transform.parent = faceCamera.transform;

        //Layerを変更
        canvas_G.layer = LayerMask.NameToLayer("UI");
        panel_G.layer = LayerMask.NameToLayer("UI");

    }

    void Update()
    {
        //Fixed Timestepを固定
        Time.fixedDeltaTime = FIXED_UPDATE_DELTATIME;

    }

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

        if (coroutine == null)
        {
            //テスト用　フェードアウト
            if (Input.GetKeyDown(KeyCode.O) && panelColor.a == 0)
            {
                FadeOut();
            }

            if (Input.GetKeyDown(KeyCode.I) && panelColor.a == alpha_Panel)
            {
                FadeIn();
            }
        }
    }


    public  void FadeOut()
    {
        if (panelColor.a == 0)
        {
            //スタートの時間記録
            startTime = Time.time;
            print("フェードアウト開始");

            coroutine = StartCoroutine(FadeOutCoroutine());
        }
    }


    public  void FadeIn()
    {
        if (panelColor.a == alpha_Panel)
        {
            //スタートの時間記録
            startTime = Time.time;
            print("フェードイン停止");

            coroutine = StartCoroutine(FadeInCoroutine());
        }
    }

    IEnumerator FadeOutCoroutine()
    {
        int count = 0;

        yield return new WaitForFixedUpdate();
        while (facePanel.color.a < alpha_Panel - 0.00005f)
        {
            yield return new WaitForFixedUpdate();
            panelColor.a += alpha_Panel / (fadeTime * 50);
            facePanel.color = panelColor;

            count++;

            //フェード中の時間、Alphaを確認
            print(Time.time - startTime);
            print("アルファの値:" + panelColor.a + ":" + count + "回目");

        }
        print("フェードアウト停止");
        panelColor.a = alpha_Panel;

        StopCoroutine(coroutine);
        coroutine = null;
    }


    IEnumerator FadeInCoroutine()
    {
        int count = 0;

        yield return new WaitForFixedUpdate();
        while (panelColor.a > 0 + 0.00005f)
        {
            yield return new WaitForFixedUpdate();
            panelColor.a -= alpha_Panel / (fadeTime * 50);
            facePanel.color = panelColor;

            count++;

            //フェード中の時間、Alphaを確認
            print(Time.time - startTime);
            print("アルファの値:" + panelColor.a + ":" + count + "回目");

        }
        print("フェードイン停止");
        panelColor.a = 0;

        StopCoroutine(coroutine);
        coroutine = null;
    }
}
```

コードの解説も書きたいことが多くて長くなりそうなので
明日続き書きます。
続き→[こちらです](https://qiita.com/OKsaiyowa/items/85b167cccf811882bf1b)