2022-02-12

【Unreal Engine】極少ノード数でリアルな水マテリアル

非常に少ないノード数にもかかわらず本格的な水マテリアルを作りながら難しいノードの意味を解説する。

Article Image

水のマテリアルを作る

水の表現は色々あるが、とにかくサクッと作れて結構リアルな作り方がある。

まずは作例を作ったので次の映像を見てもらえたらと思う。

ちょっと変わった作り方

この記事ではオパシティを使わずに透明感と歪みを表現するちょっと変わった作り方となっている。

良くあるタイプのシンプルな水マテリアルとはちょっと違う実装だと思うのでご注意。

あくまで作成方法の一つとして捉えてもらえれば。

この記事を作るきっかけとなった映像

この記事で使っているマテリアルのソースそのものは次のYoutube動画(英語)の中で紹介されているもの。

1:Refraction and Distortion with Scene Colour in UE4 - YouTube

また、次のUnreal Engine公式動画(日本語)にて紹介されている水マテリアルの基礎概念になっているものかと思う。

2:UE4で学ぶ水中表現(UE4 Environment Art Dive) - YouTube

※両作者様、この場を借りてお礼申し上げます。

この記事の目的

正直水マテリアルを作るだけならば上の動画1を見てもらえば誰でも簡単に作れる。

そこで、この記事では水マテリアルの紹介に留まらずノードの理解を深めてもらえる記事を目的とする。

また、英語解説が苦手という人も多いだろうという想定に加え「Scene Color」という検索しても全くヒットしないノードが出てくるため、まさに謎技研で取り扱うべき話題だと考えた。

完全に初心者向けとはいかないかもしれないが、私が分かる範囲でこのノードの本質に近づけたらと思う。

またこの記事では上の映像のノードを少し改造し、見た目を調整する方法も加える。

読者のレベル

初心者でも読めるレベルに近づけるつもりではあるが、基礎的なノードは解説しきれない。

赤ノード以外はよく使うものばかりなので別途調べてもらえればと思う。

この表現のメリット

この方法で実装すると次のメリットがあると考える

  • 5分で作れる
  • 動作が軽い
  • 結構リアルに見える
  • 極めるとめっちゃ美しい作品が作れる(冒頭動画2)

処理の重さを目視する

先にマテリアルが軽いということを確認しておく

シェーダー複雑度(Shader Complexity)というのを確認すると重さがわかる。

シェーダー複雑度

次のシーンで比較した。

シーン

結果

全体が完全な緑色になっており、かなり軽い実装であることが分かる。

この表現のデメリット

デメリットもいくつか感じる

  • カメラのピントによるボケが表現できない(他はボケるのに水面だけボケにならない)
  • 水の色みをコントロールするが難しい
  • 板ポリに張るだけなので、水の中に入るようなゲームは別の実装が必要
  • スクリーンショット映えしない(次で解説)

スクリーンショット映えしない

ゲーム内で見ると美しい揺れになるのだがこのノードだけでは色みを出すのが難しいのでSSにしてみると決して悪くはないのだが透明すぎて「あれ?」となると思う。

上から

というわけで、もう少し色味というか水中の乱反射を表現する改造が必要。

が、この記事ではそこまで深くは取り扱わない。

マテリアルを見てみる

実際に使用されているマテリアルは、板ポリに貼り付けただけの非常にシンプルなもの。

板ポリ

ノード

そしてノード数はたったのこれだけ。

ノード概要

Blend Modeに注意

一点だけ制限がありBlend ModeTranslucent, Additive, AlphaCompositeのどれかでないと動作しない。

マテリアルノード読み解く

できるだけ初心者でも理解出来る記事にしたい。

というわけでここからは個別のマテリアルノードが何をしているかを読んでいく。

ただ、残念ながら私も完全には理解しきれていないので参考程度として読んでもらえたらと思う。

Screen Position ノード

まずよくわからないと思うのがScreen Positionノード。

Screen Position

調べてみるとPostProcessVolume用のマテリアルを作る時に使われているような情報がちらほらヒットする。

今回は普通のマテリアルに適用しているが、ともかく具体的に何が起こるのかを見ていく。

直接エミッシブカラーにつないで見る

直接エミッシブカラーにつないで板ポリでプレビューすると次のようになる。

ScreenPositionを直接繋ぐ

これはTexCoordノードを繋いだときとカラーが似ているが...ちょっと色が薄いように見える。

ノードの出力名を見れば分かるがTexCoordと同じでUV(RとGの2値)が出ているのは間違いなさそうだ。

板ポリをプレビュー画面に張り付くほど拡大してプレビューすると...

拡大画像

色が濃くなった。

もうちょっと分かりやすくするためにこの状態でRだけマスクしてみよう。

Rだけ抽出

白黒

わかっただろうか? まだわからないだろうか?

ちょっと板ポリを傾けて見る。

傾け1

傾け2

これで伝われば良いのだが...

つまり何が起こっているのかというと

板ポリが画面左の枠に近づくほど黒で表示されている(逆に右端にくっつけると白になる)

カメラからの距離(奥行き)は完全に無視で、常に画面の端との距離が出ているようだ。

次はGをマスクしてみてみれば

Gをマスク

今度は画面の上で黒、下で白へと変化する。

画面端かどうかを取っている

というわけで、このノードはポリゴンがどんな距離(角度)であろうとユーザー側の画面端との距離が色で表される

今回とは別に、画面端との距離で変化するマテリアルを作りたい場合は有用そうだ。

Scene Color

次にScene Color

こちらを直接エミッシブカラーにつないで見る。

Scene Color

例としてゲーム上に配置したキューブにマテリアルを入れてみることにする。

キューブ

適用後は次。

適用後キューブ

「なんだ、透明になっただけじゃないか」と思う人もいるだろう。実際に透明に見えている。

ここで重要なのはエミッシブカラーに繋いだ状態で透明になっているということだ。

通常透明にするにはオパシティを利用する必要があるが、こちらには何もつながっていない。

「いんや、これはマテリアルがバグってるだけだね」という人もいるかもしれない。

ちょっとだけ弄ってみよう。

multiply

Scene Colorの出力に0.3をかけてやることによって色を暗くする効果がある。

さて、どうなるか。

半透明暗め

確かに半透明のまま暗い色になった。

マテリアルがバグって非表示になっているわけでなく正しく色が透けていると考えて良い。

つまりオパシティを使わずに透過の表現が出来る。

透明にしたいならオパシティ使えば良くない?

本当に透明にしたいだけならオパシティに0~1を入れてやれば透明(半透明)になる。

その状態でNormal屈折にノードを繋いでいけばほぼ同じクオリティの水表現はできるようだ。

※冒頭の動画1ではこちらの方法も紹介されている

しかしながら(すくなくとも私の能力では)このコントロール方法だと調整が難しく、思ったように描画されないことがあった。

というわけでここからはScene Colorと合わせて実際に水マテリアルにしていく。

Scene Colorをどう使うのか

すでに気付いた人もいるかと思うがScene ColorにはUVsという入力がある。

ここにUVを入れてやれば光の空間を歪めることができそうなイメージは湧く。

やってみよう

TexCoordを繋いだらどうなる?

Texcoord

上のノードでマテリアルを適用すると

なんか変

なんかとても不自然な状態になった。

しいて言えば昆虫の擬態のような。

ここにTexCoordを繋ぐのは違うようだ。

ScreenPositionを繋ぐと

さて、ここにScreenPositionを繋いだらどうなるのだろうか。

ScreenPosition

結果は...

透明

ん?何も起こらない?

と思うかもしれない。

これはつまり(恐らく)Scene ColorUVsに何も入力しなかった時と同じUVが入力されたとも言える。

※つまりTexture Sampleノードに直接TexCoordを繋いだのと同じような意味 = 何も起こらない

UVを変形すれば歪められる

ということはTexture Sampleと同じようにこのUVを歪めてやることで空間を歪めることができそうだ。

そして冒頭で出したノードにすることでゆらゆらと揺れる水面を表現できる。

ノード概要

最も重要なのはScreenPositionScene Colorの間にAddノードが入っているということ。

これにより直接UVを歪めているというワケ。

作例

※スクリーンショットが分かりにくいので、かなり派手に調整

このままアニメーションなしで「氷」や「ゼリー」として扱っても使えるかもしれない。

色付けが難しい

表面はゆらゆらしているが、乱反射的な色合いがどうしてこれでは表現できない。

ベースカラーに青を流すと次のようになる。

青色に設定

これはこれで悪くないのだが、リアルさが逆に失われがち。

このあたりは別途研究が必要そうだ。

基本ノードをちょっと解説

ほかは基本ノードなので詳しくは解説しないが、わからない人向けにちょっとしたヒントを残しておく。

TexCoordで波紋の広がりを調整

冒頭で紹介した動画になかったノード。この記事用に追加した。

TexCoord

ここにTexCoordを入れてTilingの数値を調整することで波紋の広がりが調整できるようにしてある。

Tiling設定

隣のPannerというノードを挟むと、テクスチャがズレていくアニメーションにできる。

これが川が流れているような効果へつながる。

Texture Sample

ここには波紋っぽいアルファ画像ならなんでも良いと思う。

私のサンプルではデフォルトで入っているT_Water_Nというテクスチャを利用した(たぶんノーマル用画像だが割と使える)

なんでMultiplyしてるの?

Multiply

テクスチャそのままUVにaddすると波紋の歪みが強く出過ぎるため少数を乗算して薄めている。

0.1

1.0

なんでRGでマスクしてるの?

RGマスク

この後UVとaddするため。

UV画像はRとGの要素しか持たないためここでマスクしないとadd後の結果がおかしくなってしまい、マテリアルそのものが描画されなくなる。

Texture Sample側にRとGが別々に出ているので、こちらから別々で計算してAppendでRGに戻しても良い。

背景アセットがリアルすぎて気になる

こちらはMegascansからDLさせていただいたもの。

Unreal Engine内で使う場合は無料なので要チェック。

※シーンそのものは私がMegascansを組み合わせて作ったもの

Megascans と Unreal Engine でデジタルワールドを作成する

おまけ:Waterシステムというのもある

今回はあくまでマテリアルを使って水を表現した。

ただ、Unreal EngineにはWaterシステムというプラグインが実装されており、より波打ちにこだわった表現が簡単にできる。

Water System Deep Dive | Inside Unreal - YouTube

とても便利そうなのでマテリアルから考えるのが面倒ならこちらから使ってみるのもアリかと思う。

以上

正直、水のマテリアルは表現方法が色々あるのであくまで一例として捉えてもらればと思う。

また冒頭に挙げた動画2のようなマテリアルが作れるようになればユーザーを驚かせるクオリティに仕上げることもできそうだ。



この記事をシェア


謎の技術研究部 (謎技研)