眠くなっちゃった

気持ちで書きます

Skyboxの色をスクリプトから変えたときの出来事

Unity Editorにて「バグのようなそうではないような...なんというか...」って感じの挙動を見つけたのでとりあえず書きます。

やってしまったこと

2つのSkyboxのマテリアルを用意してそれをスーッと切り替える、つまりSkyboxのクロスフェードをしたかったわけです。 そして「ColorならLerpあるけど、さすがにMaterialにはないよな~」なんて思ってたら、ありました。

docs.unity3d.com

「Shaderもあればテクスチャもあるのにマジか...Unityってすごい...」と思い使ってみることに。こんな感じにスクリプト(色々省略してます)を書きました。

RenderSettings.skybox.Lerp(a, b, t);

いざ再生!! ...色が変わっただけでした。まあ...そうですよね...現実は甘くない。ちなみにこれtsubaki_t1さんが3年前に見つけてました。

tsubakit1.hateblo.jp

で、がっかりするだけでは終わりませんでした。

起きたこと

停止すると、Skyboxが元に戻りませんでした。え?と思ってSkyboxに適用したMaterialを見てみると、Tint Colorの値が変わってました。ちなみに僕は上のスクリプトのbのMaterialのカラーをRGBAで(0,0,0,0)にしてたので空が真っ暗になりました。恐ろしかったです。何が怖いって、場合によっては元の色の設定値がわからないと戻せないことです。しかも、SkyboxにはDefault-Skybox(Unityのビルトインのやつ)だったのでDefault-Skyboxが真っ黒になり、Projectビューから選択して編集もできないのでインストールしなおしか...ってなりました。

解決?

そのときは、なんとなく新しいマテリアルを作成したらDefault-Skyboxが元に戻りました。Materialを新規作成した際に再読み込みが走って元のデータをUnity Editor上で反映させたのかな、と思い、別のマテリアルを用意して実験。作ったマテリアルをSkyboxに設定し、上のスクリプトを実行して色が変わるのを確認して、新しくマテリアルを作成、と同じようにやってみても元に戻りました。

あと、"RenderSettings.skybox.SetColor("_Tint", color);"として色を変えた場合も同様にマテリアルの色が完全に変わってしまいました。こちらの怖いところは、マテリアルを新しく作っても元に戻らないことです。

しかしこれだといちいち再読み込みさせないといけないってことだからめんどくさい...。そこでスクリプトに以下のようなものを追加。

void OnApplicationQuit() {
    RenderSettings.skybox.SetColor("_Tint", firstSkyboxColor);
}

firstSkyboxColorはpublicなメンバ変数で、あらかじめ最初に設定したSkyboxのマテリアルのTint Colorの値を手動コピーしておく感じです。雑すぎるしあまり解決にはなってない気がする...。

考察

Material.Lerpの使用時の挙動を見ると、RenderSettings.skyboxはUnity Editor上で元データからコピーしたものを扱っているように見えます。それに対して、Material.SetColorの使用時の挙動を見ると、元データを書き換えているように見えます。まあどちらも静的メソッドではなく、インスタンスのメソッドだからそういう挙動をするのは当たり前のような気がします。というか、参照っていうだけのことでは...。参照だから、参照先を変えるだけみたいな下のコードは問題ないっぽいですし...。

RenderSettings.skybox = mySkybox;
DynamicGI.UpdateEnvironment();

結論

詳しくはわかっていないので迂闊に使わない方がいい気がする(まあ僕は必要に迫られているのでSetColor使ってごり押ししますが)。Skyboxのマテリアルの色を元のデータを変えずに変えるいい方法ないですかね...。