[Unity] Oculus Utilitiesに含まれているOVRScreenFade(フェード)が面白かったのでメモ


通常のゲームであればPost Effectでフェードイン・アウトを実現すれば比較的簡単に実装できると思う。
が、以前の記事で書いた方法をVRで試すとうまく行かなかった。
(使っているCardboard SDKとの相性の問題もあるかも。(おそらく)歪みをPostEffectで処理しているせいだと思ってる)

で、Oculusではそのあたりどうしているのかというと、どうやら画面全体を覆う板ポリを描いてそれを徐々に黒くする(あるいは黒から透明にする)という方法で実現しているみたい。(板ポリはあくまで概念で実際にはピクセルシェーダを操作しているんだと思うけど)

C#コード

Utilityに含まれているCSコードは以下のようになっている。

using UnityEngine;
using System.Collections;

public class OVRScreenFade : MonoBehaviour {

    public float fadeTime = 2.0f;
    public Color fadeColor = new Color(0.01f, 0.01f, 0.01f, 1.0f);

    private Material fadeMaterial = null;
    private bool isFading = false;
    private YieldInstruction fadeInstruction = new WaitForEndOfFrame();

    void Awake() {
        fadeMaterial = new Material(Shader.Find("Oculus/Unlit Transparent Color"));
    }

    void OnEnable() {
        StartCoroutine(FadeIn());
    }

    void OnLevelWasLoaded(int level) {
        StartCoroutine(FadeIn());
    }

    void OnDestroy() {
        if (fadeMaterial != null) {
            Destroy(fadeMaterial);
        }
    }

    IEnumerator FadeIn() {
        float elapsedTime = 0.0f;
        fadeMaterial.color = fadeColor;
        Color color = fadeColor;
        isFading = true;
        while (elapsedTime < fadeTime) {
            yield return fadeInstruction;
            elapsedTime += Time.deltaTime;
            color.a = 1.0f - Mathf.Clamp01(elapsedTime / fadeTime);
            fadeMaterial.color = color;
        }
        isFading = false;
    }

    void OnPostRender() {
        if (isFading) {
            fadeMaterial.SetPass(0);
            GL.PushMatrix();
            GL.LoadOrtho();
            GL.Color(fadeMaterial.color);
            GL.Begin(GL.QUADS);
            GL.Vertex3(0f, 0f, -12f);
            GL.Vertex3(0f, 1f, -12f);
            GL.Vertex3(1f, 1f, -12f);
            GL.Vertex3(1f, 0f, -12f);
            GL.End();
            GL.PopMatrix();
        }
    }
}

やっていることはシンプルで、このスクリプトが読み込まれたタイミングで処理が始まり、毎フレームごとに FadeIn メソッドが呼ばれるようにしている。
そしてその処理の中で徐々にマテリアルの色を透明にしていく(=フェードイン)という流れだ。

OnPostRender メソッド内の GL クラスがなんなのかまだ調べてないけど、シェーダに対する処理なのは間違いない。で、内容的には Z値だけ若干カメラの奥方向に移動した四角形を描いてそれをシェーダに送っているのだと思う。

GL - Unity - Scripting API

シェーダコード

シェーダのコードは驚くほどシンプル。
Z値に対する書き込みをオフにし、普通の透過処理に必要なブレンドモードにした上で、あとは色を設定しているのみ。
Pass になにも書かれていないのはC#のコード側で SetPass されるためと思う。

Shader "Oculus/Unlit Transparent Color" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
    }
    SubShader {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Opaque" }
        LOD 100

        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha
        Color [_Color]

        Pass { }
    } 
}

以上、Oculus Utilitiesに含まれているフェードの仕組みでした。
こうした既存のものを参考にするのはとても勉強になるなぁ。