目指すもの
スカイボックスを滑らかに切り替える
はじめに
使用する天候アセット: Customizable skybox
実装までに試したこと(※飛ばしても大丈夫)
最初はRenderSettings.skybox.Lerp
で実装しようとしたが,Skyboxを元のマテリアルに戻せなくなった
原因は,RenderSettings.skybox.Lerp
が直接的にスカイボックスをレンダリングに反映しないためらしい
解決するには,スカイボックスのプロパティを手動で補間する必要があり,面倒だったので別の方法を考えた
参考: https://ykun33.hatenablog.com/entry/2016/08/15/142553
実装コード
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChangeSkybox : MonoBehaviour
{
public Material daySkybox;
public Material nightSkybox;
public float transitionDuration = 10.0f;
private float transitionTime = 0f;
private bool isTransitioning = false;
private bool isDayToNight = false;
void Start()
{
// Skyboxの初期設定を昼(daySkybox)に設定
RenderSettings.skybox = daySkybox;
}
void Update()
{
if (isTransitioning)
{
transitionTime += Time.deltaTime;
// トランジションの進行度を0〜1の範囲にクランプ
float t = Mathf.Clamp01(transitionTime / transitionDuration);
// 昼 -> 夜 or 夜 -> 昼
// 条件分岐によって,skyboxを設定
RenderSettings.skybox = isDayToNight ?
BlendSkybox(daySkybox, nightSkybox, t) :
BlendSkybox(nightSkybox, daySkybox, t);
Debug.Log("The transition is in progress");
// トランジションが完了したら実行
if (t >= 1f)
{
isTransitioning = false;
transitionTime = 0f;
Debug.Log("The transition is completed");
}
}
// テスト用
// 現在は手動でskyboxの遷移を行うが最終的には自動的に変更したい
if (Input.GetKeyDown(KeyCode.Space))
{
StartTransition();
}
}
public void StartTransition()
{
isTransitioning = true;
transitionTime = 0f;
// 昼か夜かを保存する変数の値切り替え
isDayToNight = !isDayToNight;
}
// 2つのスカイボックスを線形補間して混合する
private Material BlendSkybox(Material skybox1, Material skybox2, float t)
{
Material blendedSkybox = new Material(skybox1);
blendedSkybox.Lerp(skybox1, skybox2, t);
return blendedSkybox;
}
}
解説
初期設定
public Material daySkybox;
public Material nightSkybox;
public float transitionDuration = 10.0f;
private float transitionTime = 0f;
private bool isTransitioning = false;
private bool isDayToNight = false;
-
daySkybox
とnightSkybox
はそれぞれ切り替えるスカイボックスのための変数です -
transitionDuration
は名前の通りです.public
で宣言しているのでインスペクター画面にて値を変更できます -
transitionTime
はトランジションの実行時間を測るための変数です.トランジションの実行度を計算するときに使います -
isTransitioning
はトランジションが実行しているか,isDayToNight
はスカイボックスの遷移が昼->夜または夜->昼かどうかを判定するための変数です
void start()
- ここではSkyboxの初期設定を行なっています
アップデート関数
if (isTransitioning)
- トランジションを実行するかどうかを判定します
スカイボックスの切り替えている部分
...
transitionTime += Time.deltaTime;
// トランジションの進行度を0〜1の範囲にクランプ
float t = Mathf.Clamp01(transitionTime / transitionDuration);
// 昼 -> 夜 or 夜 -> 昼
// 条件分岐によって,skyboxを設定
RenderSettings.skybox = isDayToNight ?
BlendSkybox(daySkybox, nightSkybox, t) :
BlendSkybox(nightSkybox, daySkybox, t);
// トランジションが完了したら実行
if (t >= 1f)
{
isTransitioning = false;
transitionTime = 0f;
}
...
- トランジションの進行度
(transitionTime / transitionDuration)
を0〜1の範囲にクランプし,進行度に応じてスカイボックスを切り替えています-
Mathf.Clamp01
: https://docs.unity3d.com/ScriptReference/Mathf.Clamp01.html - 三項演算子(Ternary conditional operator): https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator
-
- トランジションが完了
if (t >= 1f)
したらisTransitioning = false;
でif
文を抜けています.また,次回のトランジションのためにtransitionTime = 0f;
を初期化しておきます
トランジションの開始のためのコマンド
...
if (Input.GetKeyDown(KeyCode.Space))
{
StartTransition();
}
...
- 今回はスペースボタンを押すことでスカイボックスの切り替えを行います
-
Input.GetKeyDown
: https://docs.unity3d.com/ScriptReference/Input.GetKeyDown.html
-
-
StartTransition();
については後述します
トランジションの開始
...
public void StartTransition()
{
isTransitioning = true;
transitionTime = 0f;
// 昼か夜かを保存する変数の値切り替え
isDayToNight = !isDayToNight;
}
...
- スペースボタンを押すことで
StartTransition()
が実行されトランジションに必要な値の設定を行います - この関数により
isTransitioning
がtrue
になることでupdate()
内の処理が実行されます
スカイボックスの混合
...
private Material BlendSkybox(Material skybox1, Material skybox2, float t)
{
Material blendedSkybox = new Material(skybox1);
blendedSkybox.Lerp(skybox1, skybox2, t);
return blendedSkybox;
}
...
- Materialクラスのインスタンス blendedSkyboxを作成して,Material.Lerpメソッドを使用で2つの天空ボックスを徐々にブレンド(線形補間)する方法で実装
最後に
目指した通りの動きが実装できましたか?
現在は手動でスカイボックスの遷移を実行していますが,トランジションの開始のためのコマンドを変えることでさまざまな実行の仕方ができるので,それぞれの目指す方法で構築してみましょう
お疲れ様です🥳