見出し画像

【UE5】エフェクターに捧げるFake Reflection~嘘つきな反射~

皆さん、エフェクト作ってますか?

僕は最近マテリアルばかり作ってます



さて、今回のNOTEは、「Fake Reflection」です
なぜFake(フェイク)なのか?

それは、

反射は重い

嘘の反射をいれちゃおうぜ

だからです


反射についてはネットで調べれば基礎的な知識は得られると思いますが、リアルな反射をしようと思うと・・・・

めちゃくちゃ重い・・・・

しかも

エフェクトにちゃんとした反射なんて必要あるの?
逆に反射させたいけど、綺麗に反射できないじゃん
と思ったことは数知れずだと思います

そこで、色々方法はあると思うのですが、今回割りと現場で使える2種類の方法をご紹介致します



反射の比較


今回紹介するやり方としては、

  • HDRI画像を反射させる

  • HDRI画像を加工してそれっぽく反射させる

の2パターンです

まずは、それぞれがどんな反射になるのか、通常反射と比較してご覧ください

Left: NormalRef Center: HDRI Right: Fake

左:通常の反射
真ん中:HDRI画像を反射に使用したもの
右:フェイク反射

環境マップから反射させちゃう


準備

まずは、HDRI画像選びから

自分は、よく以下サイトのHDRIにお世話になっております。
今回は、「studio_small_09_1k.hdr」を選択

今回は、「studio_small_09_1k」を選択


もちろんレベルからHDR画像を作成しても問題ありません

使用時の注意点

軽いと言っても、、、、キューブマップ(特にHDRフォーマットの画像)は通常の2Dテクスチャに比べてデータ量が大きく、計算も複雑であるため、パフォーマンスへの影響は大きくなりがちです
使用する場合は、プログラマーさんに負荷調査を依頼してから使用しましょう

LOD設定で高解像度のものにしたい時などに使用して、あとは後ほど紹介する軽量の方法で実装するのもおすすめです

マテリアルの設定

今回後述するFakeRefと同マテリアル内で作ってます
スイッチパラメーターで、
・HDRI画像の反射にするか
・フェイク用の反射にするか
を切り替えで選択できるように作っております

↓こんな感じ↓

Shading ModelはUnlitにしております
※おそらくエフェクターはLitをあまり使わないので、その想定です

さて、ダウンロードしてきたHDRI画像をドラッグ&ドロップでUE5プロジェクトに読み込ませて下さい

そうすると自動でTexture Cubeというテクスチャー形式で読み込まれます

ちなみに、TextureCubeとは、立方体の6つの面(上下左右)にテクスチャを配置したテクスチャー形式です
↓このイメージ↓

HDRI画像の反射はそのままつなげば終了です
先ほどのマテリアルノードで言えばこちらの流れが該当します

HDRI画像をそのまま繋いだので、環境マップとの違和感なし

FakeRef用の画像で反射させちゃう

準備


次に、FakeRef用の画像を準備しましょう
DCCツールなどで細かく割った球体を準備します
(自身は、Houdiniがメインツールなのでそちらで説明致します)
※他のツールでもやることは変わりません

球体の作成図
アサインしたマテリアル

使用したノードはこのような感じです
envlight_fromTextureHeavenには、ダウンロードしてきたHDRI画像を貼っております

それをカメラが収まるぎりぎりまで映して下さい
ちょっとでも隙間があるとだめです
ぎりぎりを攻めてください
この辺は対象のジオメトリが収まるような仕組みを作った方がいいですが、今回は割愛します
※カメラの画角と対象との距離で、カメラの距離は数式で作れるかと思います

カメラの設定

そして、それをレンダリングします
今回はpngでの出力です
(筆者は重すぎる形式を避けて生きてきたのでpngにしてます。調べて頂ければわかると思いますが、tgaよりも軽く、jpgよりも綺麗なので好んでpngを使います)


マテリアルの設定


先ほどのマテリアルに作った画像を入れてください

ここで、何やら身に覚えのないノードやら、細々と何かしていると思います。

解説


Reflection Vector

Reflection Vector(反射ベクトル)Rは、
 ・視線ベクトル(V、カメラから表面に向かうベクトル)
 ・法線ベクトル(N、法線)
で求められてます

視線ベクトルVは、「カメラの位置とピクセルの位置を結ぶベクトル」で、UE5では自動で計算されCameraVectorとして提供されてます

反射ベクトルは以下式から求められます

R = V - 2*(V・N)*N
※「・」は内積

Lumenでは、この反射ベクトルを元に、
 1:仮想的なレイ(名前の通り光線をイメージ)を飛ばす
 2:シーンのオブジェクトに衝突するまで追跡
 3:レイが衝突したポイントの色情報(テクスチャ、色の影響など)を取得
して、色情報をマテリアルに反映してます

Houdiniで簡易的なレイキャストのイメージをつくりました

厳密ではないので、あくまでイメージです
この緑色の線が向いている方向が反射ベクトルです
この方向にカメラからレイ(光線)を飛ばして何かに当たったらその色情報を取ってくるくらい」の感じで大丈夫だと思います

このReflectionVectorのXY(画像だとRとG)を抜き取って、0.5を掛けて0.5を足しているのは、
Reflection Vectorの値をUV座標に変換するための操作です

Reflection Vector値は、基本的に-1.0から1.0の範囲内にあります
なので、0.5を掛けて0.5を足すことによって0.0から1.0の範囲にしてUV座標として利用しているんですね
Z成分(奥行きの成分)は2D環境マップには不要なので、XYで計算してます

Reflection Vectorの値はノーマライズされて返ってくるので、単位円内の返り値となります
下記は、Reflection Vectorを計算し、UVにそれぞれ入れたものです
カメラの位置が変わるたびにUVは更新されますが、単位円内の返り値になるのがわかるかと思います

Reflection Vectorのサンプル

画像のレンダリングにぎりぎりを攻めて下さいとお伝えしたのでこのためです

結果は、こんな感じです
HDRI画像をそのまま張り付けるよりかは、シンプルな形状だとちょっと違和感のある見た目ですが、疑似的な反射としては使えると思います

Fake Reflection

最後に

エフェクターが使用する反射は

1:HDRI画像の反射を使用する
2:HDRI画像から反射用のテクスチャを用意して疑似的に反射させる

の2択から考えてみてください

1と2は、LODによって切り替えれるように負荷対策をしっかりと行いましょう

 以上、読んでいただきありがとうございます!もしこの記事が役に立ったり、楽しんでいただけたら、ぜひフォローして他の記事もチェックしてみてくださいね!😊

いいなと思ったら応援しよう!