UnityのRealtimeGIを試してみる（Emissionのオンオフをしよう）

#はじめに
こんにちは、ここ数週間めっきり記事を書かなくなってしまいました。ちょっとゲーム作るの楽しくなっちゃって…

最近作っているVRコンテンツで、なんとなくリアリティを追求しようという気持ちになりまして、ライティングとか立体音響とかを触っています。
今回はその際に用いたライティング技術の一つである、GI(GlobalIllumination)を触ってみようという記事を書こうと思います。
#どんなものが出来るの？
![4d616dda72f79ab95a5731438bb0f190.gif](https://qiita-image-store.s3.amazonaws.com/0/256231/f5f44d40-72e5-49fe-88a1-b3b7cff801f7.gif)
前方にあるのは鏡です。パイプの光の色が壁面に反射していることがわかりますね。エモい。
こういうのができます。反射光とPostProcessingStackのBloomはUnityライティングの花形感があります。実装だけならお手軽ですしね。
#実装
##GlobalIlluminationってなんぞや
GlobalIllumination(以下GI)とは、レンダリング技法のひとつで、日本語で言うと「大域照明」となります。古典的なレイトレーシングである局所照明に比べると、ある物体の反射光が間接的に他のオブジェクトを着色する様子や屈折によって光が一部分に集合し、そこだけ明るくなるコースティクスといった現象の表現が得意なようです。
[Wikipediaの記事](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E3%83%BB%E3%82%A4%E3%83%AB%E3%83%9F%E3%83%8D%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)
UnityにはEnlightenというGIのミドルウェアが統合されており、これのおかげでGIによるレンダリングが出来るみたいです。
GIの照度マップはオブジェクト毎にベイクされているようで、Emissionの設定によってはランタイムで光源の色や強さを変えることができるようです（上記のgif参照）。これを使えばエモライティングが出来そう…？
##GIを実装してみよう
御託はいいからって感じですかね。試しにGIの威力を見てみましょう。
真面目で勤勉な皆様のためにここにいつもの「レイトレーシングしないと出られない部屋」をご用意いたしました。
![キャプチャ281.PNG](https://qiita-image-store.s3.amazonaws.com/0/256231/a6016315-5f39-c637-b33a-d76e868bd50b.png)
各オブジェクトのMeshRendererのプロパティである、LightmapStaticをオンにします。
![キャプチャ280.PNG](https://qiita-image-store.s3.amazonaws.com/0/256231/5b069cc9-a20a-b656-641b-12bb72bfa2a8.png)
ツールバーのWindow -> Rendering -> LightSettingでライティング画面を出します。環境光の効果を除くためにEnvironmentの項目のIntensity Multiplierの値を0にしましょう。オブジェクトが真っ暗になってしまうでしょうが大丈夫です。
コレでよし。Emissionする設定にしたmaterial（ただしEmissionの設定がBakedではなくRealtimeになっていることを確認しましょう）を貼り付けた球でも置いてみましょう。Emissionマテリアルを貼り付けた球についてもLightmapStaticを忘れないように。
![キャプチャ282.PNG](https://qiita-image-store.s3.amazonaws.com/0/256231/5358363e-d15f-c04e-4ee5-7081579afb3b.png)
こんな感じになりました。雰囲気有りますね～～ただコレにも問題があって、リアルタイムにisActiveの値をいじったりすると反射光だけ残ってしまいます。
![5bf9cbc70541ce34d105fc660f9db631.gif](https://qiita-image-store.s3.amazonaws.com/0/256231/7f44a1d0-89ac-7081-2e4c-be636dcb2536.gif)

違和違和違和♥(ちゃんと照度マップを反映しないと)ダメだぞぉ♥
照度マップの特性の調整を反映するには `renderer.UpdateGIMaterials()` を使います。

```c#:GITest.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GITest : MonoBehaviour {
    public Renderer targetRenderer;
	// Use this for initialization
	void Start () {
        targetRenderer = GetComponent<MeshRenderer>();
	}
	
	// Update is called once per frame
	void Update () {
		
	}
    public void OnEnable()
    {
        Debug.Log("Enabled GI");
        targetRenderer.material.EnableKeyword("_EMISSION");
        targetRenderer.UpdateGIMaterials();
    }
    public void OnDisable()
    {
        Debug.Log("Disabled GI");
        targetRenderer.material.DisableKeyword("_EMISSION");
        targetRenderer.UpdateGIMaterials();
    }
}

```

例えば上記のスクリプトをアタッチすればemissionをactiveと同時に操作したうえでGIを更新していい感じになります。
![98e2471e8d96d41444466a18ffe43ed1.gif](https://qiita-image-store.s3.amazonaws.com/0/256231/8492df5a-e06d-af83-7e06-c1f5092d0b22.gif)

うむ。
##リアルタイムに光源の特性を変更してみよう
色々変更した上で先述の `renderer.UpdateGIMaterials()` を使えばリアルタイムに光源の特徴を変更できます。
###色を変えよう
![2e2f51090ebe795d858b31d4ea97b266.gif](https://qiita-image-store.s3.amazonaws.com/0/256231/ce465252-0e67-0d09-7cd2-4689c8ee6f33.gif)
GIでは色は照度マップの形状自体には影響を及ぼさないので色を変えてもいい感じのライティングを維持することができます。color自体にEmissionのIntensityは含まれていません。colorに乗算する値がIntensityとなるようです。

```C#
    public void ChangeColor(Color newColor)
    {   
        color = newColor;
        targetRenderer.material.SetColor("_EmissionColor", color * intensity);
        targetRenderer.UpdateGIMaterials();
    }
```

###強さを変えよう

![54b1e18261ba4b72c9dcb03fcab5d0fe.gif](https://qiita-image-store.s3.amazonaws.com/0/256231/7c0addbd-6e14-4049-616e-700d36e23a2d.gif)

Intensityも同じように照度マップの形状に影響を与えないので変更してもいい感じのライティングを保つことができます。上記と同様のコードで

```C#
    public void ChangeIntensity(float newIntensity)
    {   
        intensity = newIntensity;
        targetRenderer.material.SetColor("_EmissionColor", color * intensity);
        targetRenderer.UpdateGIMaterials();
    }
```
とすれば明るさを変更したうえでGIレンダリングの様子を更新することができます。
#最後に（RealtimeGIは万能なのか？）
ここまで結構ランタイムでも光源を変化させられる例をお見せしてきました。結局このRealtimeGIは万能なのでしょうか？
もちろんそんなことはありません。LightmapStaticなので位置を変更できないのはもちろん、純粋にベイクされた光源に対して若干精度が悪い、照度マップ自体は事前にベイクされたものなのであまりにも初期状態とかけ離れた設定にするとおかしくなる、などの欠点があります。
確かに簡単に見た目を盛れるので魅力的ではありますが、用法用量を守ってお使いになるのが良いでしょう。