imog

主にUnityとかの事を書いています

UnityのSkyboxを動的に弄る

会話の流れで、「Skyboxって動的にいじれるのかな」と思って調べたやつ。

Skyboxの情報を弄って動的に色を変えるやり方です。 http://i.gyazo.com/e690686477b66031ce47fa5bc66f605c.gif

マテリアルを準備しよう

なにはともあれSkyboxに使うマテリアルを新規作成。

今回は MySkybox という名前で新規マテリアルを作った。 使用するシェーダは、未設定時に使われている default-skybox と同じ Skybox/Procedual をつける

http://i.gyazo.com/d1f585228698f90571122b85f482eac1.png

window->lighting からLightingのメニューを開いて、 Environments Lighting の SkyboxにMySkyboxを指定する。

http://i.gyazo.com/4314db20dc0b7874fe2036ef84a651f9.png

下準備はOK

Skyboxの情報はどこにあるの?

RenderSettings.skybox でMaterialクラスのインスタンスが取得できます。シーンのライティング情報はこの辺に格納されている模様。

じつはこれを見つけるのに一番時間かかった。

どうやって色を変えるの?

RenderSettings.skybox.color の色を変える・・と思いきやそれだとエラーが出る。

Material doesn't have a color property '_Color'
UnityEngine.Material:get_color()

Skyboxは _Color プロパティーを使用していないのでこれは使えない。

というか、 Color プロパティて GetColor("_Color"); をやっていたのね・・。

シェーダが _Color を持っていないので、ちゃんと正しい名前を指定する必要がある。

Skybox/Procedualシェーダは以下のプロパティを用意している

  • _SunSize
  • _AtmosphereThickness
  • _SkyTint
  • _GroundColor
  • _Exposure

http://i.gyazo.com/b046698208406461a4af33fbcd8f2884.png

Unity上で表示される場合は右側の 「_」無しだけど、シェーダ側では左側の名前で持ってるので間違えないように注意。

この中で空の色を扱っているのは _SkyTint なので、これを取り出して値を弄ればよさそう。

実際にいじろう

以下は、毎フレーム空の色を -0.03して最終的に真っ暗にする処理です。

UniRXを使ってますが、あまりそこは気にしなくていいです。

   void Start ()
    {
        Material m = new Material(RenderSettings.skybox);
        RenderSettings.skybox = m;
        Observable.EveryUpdate().
            Subscribe(_ =>{
                var c = m.GetColor("_SkyTint");
                c.r -= 0.03F;
                c.g -= 0.03F;
                c.b -= 0.03F;
                m.SetColor("_SkyTint", c);
            });
    }

実行結果は記事トップのgifのようになります。

マテリアルのインスタンスからGetHoge、SetHogeでシェーダの任意の変数にアクセスできるので、 今回は _SkyTint のColor情報を取ってきて、黒くして、またセットを行っている。 ちなみにcolorが0~1の範囲超えてもエラー吐かなかったのでどこかで丸めてくれている模様。

一つ注意として、最初にインスタンスを新規で作ってSkyboxに設定している部分がある。

Material m = new Material(RenderSettings.skybox);
RenderSettings.skybox = m;

なぜわざわざ差し替えているのかというと、SkyboxはProjectフォルダのマテリアルを直接参照してるので、シェーダに値を入れたりすると、エディタ上でゲームを再生して終了しても 値が反映されたまま になってしまう。 一度直接やってしまったので、Projectフォルダの MySkybox の SkyTintの値が真っ黒のままになってしまっていて辛い思いをした。

なので、ゲーム開始時にその場で新しいマテリアルを生成してスワップすることで大元に変更を加えないようにしましょう。

GameObjectのInstantiate時と同じ考え方で大丈夫です。

Skyboxと銘打ったが、別にSkyboxに限らない話になってしまったことに気づいた。