【Unity】URPで「水中表現」を実装する方法!Volumeとフォグで水の中のようなグラフィックを実現しよう

Unity 水中表現を実装してみよう ゲーム開発

今回もUnityでのゲーム開発に関する話題で

URPで「水中のようなグラフィック」を実装する方法

をわかりやすく解説するという内容になっております。

Unityでゲームを作っているとたまに「水中に潜ったときのグラフィック」を用意したくなることがあります。ただ水中表現を行うためにはゲーム画面の見た目を変更する必要があるので、やり方がよく分からん!という方も多いのではないでしょうか。

そこでここではURPで水中表現を行うための具体的な実装方法をご紹介しますね。

今回実装する水中表現のサンプル動画

まず、今回実装する水中表現の例をGIF動画にしたのでそれをご覧いただきイメージをつかんでいただこうと思います。

Unity 水中表現の例

水中表現の設計:どのような表現を何を使って作るか?

水中表現の具体的な実装方法を解説する前に「どのように作るか?」という設計についてザックリ書きます。

まず、そもそも「水中表現」といいますが具体的にどのような表現を行えばいいかを考えましょう。一般的に水中というと下記の画像のようなイメージですよね。

水中の写真(参考画像)
水中の参考画像(画像提供:https://www.pakutaso.com/

必要そうな表現を書き出すと下記のようになります。

  • 全体的に「青っぽい」色調
  • 透明度が低い水質では先が見通しづらい
  • 泡が出ているとより水中っぽい

このような表現を実現するために今回の実装ではUnityやURPの下記の機能を使うことにしました。

  • Volume:画面の色調変更など、全画面用のエフェクトを追加
  • フォグ:水中での「先の見通しづらさ」を表現
  • パーティクルシステム:泡エフェクトを一定間隔で出す

水中表現の具体的な実装方法

では設計について把握していただいたところで水中表現の具体的な実装方法について解説していきます。

Volumeの設定方法

まずはVolumeを設定します。水中用の新しいVolume Profileを作成して下記エフェクトを追加し、それぞれ設定を行ってください。

  • Color Adjustments:「カラーフィルター」を水色に
  • Vignette:強さを「0.5」に
  • 色収差:強さを「0.5」に

これで画面が青っぽくなり、画面の端のほうが少し暗くなって水中っぽいグラフィックになります。

フォグの設定方法

次にシーンに適用するフォグの設定を行います。下記のように設定するとより水中らしさが出ます。

  • 色:濃いめの水色
  • 密度:「0.08」くらいに

泡エフェクトの作り方

最後は泡エフェクトの作り方です。…といってもこの記事はエフェクトの作り方の解説記事ではないので詳しいやり方は割愛させていただきますが、ザックリ書くと泡画像を用意してパーティクルシステムで次のように設定します。

  • 放出:「時間ごとの率」ではなく、バーストを使って一定間隔で一気に放出されるように設定
  • 生存期間のサイズ:サイズが徐々に大きくなるように設定
  • ノイズ:これを設定することで泡がゆらゆらと揺れるようになります
泡エフェクトの例

陸上と水中でグラフィックを切り替える方法

さてこれで水中表現を行えるようになりましたが、実際のゲームでは陸上と水中を行き来できるようにする場合がほとんどだと思うので

  • 陸上では水中表現をOFFに
  • 水中ではONに

といった具合にグラフィックを切り替えられるようにしたいものです。そこでVolumeとフォグについて、それぞれ切り替えに必要な処理を書いたC#スクリプトをご用意しました。参考になさってください。

注意:
下記のC#スクリプトは個人利用の範囲でご自由にお使いいただいて構いませんが、作者を偽るのは禁止とします。

Volume切り替えスクリプト

using UnityEngine;
using UnityEngine.Rendering;

public sealed class UnderwaterVolumeController : MonoBehaviour
{

	[SerializeField]
	Volume mainVolume;
	[SerializeField]
	Volume underwaterVolume;

	public void SwitchVolume(bool underwater)
	{
		if (underwater)
		{
			mainVolume.weight = 0f;
			underwaterVolume.weight = 1f;
		}
		else
		{
			mainVolume.weight = 1f;
			underwaterVolume.weight = 0f;	
		}
	}

}

Volumeのweight変数を使って陸上用・水中用のVolumeをそれぞれ切り替えればOK。上記スクリプトは一瞬で切り替わるような処理になっていますが、DOTween等を使って滑らかに切り替えられるようにすると見た目がよくなります。

なおVolumeクラスは「UnityEngine.Rendering」という名前空間内にあります。冒頭のusingを忘れないようにしてください。

フォグ切り替えスクリプト

using UnityEngine;

namespace KurokumaSoft
{

	public sealed class UnderwaterFogChanger : MonoBehaviour
	{

		[Header("水中フォグの設定")]
		[SerializeField]
		Color underwaterColor = new(0f, 0.3f, 0.5f, 1f);
		[SerializeField]
		FogMode underwaterMode = FogMode.ExponentialSquared;
		[SerializeField, Min(0f)]
		float underwaterDensity = 0.08f;
		[SerializeField]
		float underwaterFogStartDistance = 0f;
		[SerializeField]
		float underwaterFogEndDistance = 0f;

		// 元の設定を記録しておく変数
		bool defaultFog;
		Color defaultColor;
		FogMode defaultMode;
		float defaultDensity;
		float defaultFogStartDistance;
		float defaultFogEndDistance;

		void Start()
		{
			// 起動時の陸上フォグ設定を記録
			defaultFog = RenderSettings.fog;
			defaultColor = RenderSettings.fogColor;
			defaultMode = RenderSettings.fogMode;
			defaultDensity = RenderSettings.fogDensity;
			defaultFogStartDistance = RenderSettings.fogStartDistance;
			defaultFogEndDistance = RenderSettings.fogEndDistance;
		}

		// 水中に入った時に呼ぶ
		public void EnableUnderwaterFog()
		{
			RenderSettings.fog = true;
			RenderSettings.fogColor = underwaterColor;
			RenderSettings.fogMode = underwaterMode;
			RenderSettings.fogDensity = underwaterDensity;
			RenderSettings.fogStartDistance = underwaterFogStartDistance;
			RenderSettings.fogEndDistance = underwaterFogEndDistance;
		}

		// 水中から出た時に呼ぶ
		public void ResetFog()
		{
			RenderSettings.fog = defaultFog;
			RenderSettings.fogColor = defaultColor;
			RenderSettings.fogMode = defaultMode;
			RenderSettings.fogDensity = defaultDensity;
			RenderSettings.fogStartDistance = defaultFogStartDistance;
			RenderSettings.fogEndDistance = defaultFogEndDistance;
		}

	}

}

RenderSettingsクラスからフォグ設定にアクセスできるので、それを使って水中では上記スクリプトで設定した値に書き換えを行い・陸上ではフォグを元に戻すという処理を行えばOKです。

おわりに

以上、UnityのURPで水中のようなグラフィックを実装する方法について解説しました。水中表現を実装できると自作ゲームの幅が広がって面白いので、ぜひ皆さんも実装にチャレンジしてみてください。

この記事がUnityでのゲーム開発のお役に立てば幸いです。