LoginSignup
26
19

[Unity] Box Projectionで屋内シーンの反射による映り込みの品質を向上する

Last updated at Posted at 2019-12-23

これは 【unityプロ技】 Advent Calendar 2019の24日目の記事です。


Unity標準の ReflectionProbe のオプションにある Box Projection を設定することで、屋内シーンの反射の破綻を軽減して、映り込みの品質を向上する方法を紹介します。

百聞は一見に如かずということで、 Box ProjectionをON/OFF した動画を用意しました。

※画像が読み込まれるまでお待ちください Box Projection
  • Box Projection: OFF では、カメラの位置が無視されて、家具などの映り込みの位置がずれてしまっています。
  • Box Projection: ON では、カメラの位置が正しく考慮されて、家具などの映り込みの位置が正しくなっています!

環境

  • 2018.4.13f1 (LTS)
  • Build-in Rendering Pipeline および LWRP(Light Weight Render Pipeline)

Box Projectionとは、どんな技術なのか?

公式マニュアルにもBox Projectionの解説はあるのですが、ちょっと初心者には理解しずらかったので、簡単に解説をします。

端的に言うと、Cubemap(ReflectionProbe)のテクスチャをサンプリングするための反射ベクトルの向きを、カメラの位置と部屋の広さを定義するBoundingboxを考慮して補正する手法です。

普通のCubemapとの違いは、反射ベクトルの計算の違いだけなので、GPUの処理負荷もそれほど高くはありません。

反射はしていますが、レイトレをするわけではないので、RTXも不要です!

Parallax-Corrected Cubemapの解説


※Box Projectionの理論に興味がない人は、この節はスキップして本題から読んでください。
Unity標準のStandardShaderでBox Projectionは実装済みなので、理論は理解しなくても使うことはできます。


UnityではBox Projectionという名称ですが、Parallax-Corrected Cubemap とも呼ばれる手法です。

Parallax-Corrected Cubemapの具体的な理論と実装については、このスライドに非常に詳しく解説してあります。

この図は上記のスライドから引用しました。

image.png

この図を用いて簡単にParallax-Corrected Cubemapの解説を行います。基本的な考え方はそれほど難しくはありません。

まず各記号の説明をします。

  • $\vec{V}$: カメラのビューベクトル
  • $C$: ReflectionProbeの位置
  • $\vec{N}$: 法線
  • $\vec{R}$: 反射ベクトル(補正前)
  • $\vec{R'}$: 反射ベクトル(補正後)
  • $P$: $\vec{R}$と壁の交差点

$\vec{R}$ 方向をサンプリングすれば、 普通のCubemap ですが、
$\vec{R'}$ 方向をサンプリングすると視差が考慮された Parallax-Corrected Cubemap になります。

そして、図が示すように $\vec{R}$ を補正した $\vec{R'}$ は

\vec{R'} = P - C

によって計算できます。

$C$ は既知なので、 $\vec{R}$と壁の交差点である $P$ を計算すれば、$\vec{R'}$ が求まります。

ベクトルとAABBの交差判定のアルゴリズムを用いれば、$P$ は計算ができます。

HLSLによる Parallax-Corrected Cubemap の反射ベクトル $\vec{R'}$ を求める実装例です(MITライセンス)。

// Parallax-Corrected Cubemap
// https://seblagarde.files.wordpress.com/2012/08/parallax_corrected_cubemap-siggraph2012.pdf
float3 calcParallaxCorrectedCubemapReflect(float3 worldPos, float3 worldReflect, float3 cubemapPos, float3 boxMin, float3 boxMax)
{
    // AABB と 反射ベクトル の交差点 worldIntersectPos を計算します
    float3 firstPlaneIntersect  = (boxMax - worldPos) / worldReflect;
    float3 secondPlaneIntersect = (boxMin - worldPos) / worldReflect;
    float3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect);
    float dist = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z);
    float3 worldIntersectPos = worldPos + worldReflect * dist;

    // Cubemapから交差点に向かうベクトルが ParallaxCorrected された反射ベクトルになります
    return worldIntersectPos - cubemapPos;
}

壁の近似はAABBに限定しなくても交差判定ができれば何でも良いのですが、計算コストと品質のバランスを考慮してAABBが一般的に用いられるようです。

Box Projectionに対応した自作シェーダーの紹介

当初は、Parallax-Corrected Cubemapに対応したUnityシェーダーを実装するという記事を執筆する予定だったのですが、Unity標準のStandardShaderで実装済みであることを記事用のシェーダーの実装が完成してから知りました :sob:

供養のために、Box ProjectionとLightmapに対応した自作シェーダーのリンクを紹介します。

[本題] Box Projectionの設定

それでは、ここからが本題です!

Box Projectionの設定をして、最初の動画のようなシーンを作る方法をチュートリアル形式で紹介していきます!

0: 屋内のアセットを用意する

まずは屋内シーンのアセットを用意します。

今回はUnityアセットストアから Pack Gesta Furniture #1 をダウンロードして使わせていただきました :bow:

1-1: ReflectionProbeを配置する

まずは ReflectionProbe を配置します。

普通は部屋の中心あたりに適当に配置すればOKです。

今回は映り込みの品質を向上するために、ちょっとカメラの位置に寄せました。

image.png

1-2: ReflectionProbe の BoxSize と BoxOffset を設定する

部屋の広さにぴったり合うように、BoxSize と BoxOffset を設定します。

Wireframeモードにしたほうが、作業がしやすいかもしれません。

また、BoxSize と BoxOffset は ReflectionProbe の影響範囲の指定も兼ねているので、床のMeshに少しオーバーラップするようにサイズを調整する必要があります。

オーバーラップしないと、ReflectionProbe の影響範囲外となってしまいます。

image.png

image.png

1-3: Box Projection等の設定とBake

ReflectionProbeの設定を変更します。

  • Box Projection: ON
  • Type: Baked
  • その他はお好みでOK

設定が完了したら、 [Bake] ボタンを押して、Cubemapのテクスチャを生成します。

image.png

2: 床のマテリアルの設定

床のマテリアルを反射が見えやすく調整します。

  • StandardShader を設定(ReflectionProbeに対応していれば何でも良い)
  • Metalic: お好みですが、フローリングの床感を出すなら 0.2 前後あたりがいい感じです
  • Smoothness: 1.0 に近づくほど反射がハッキリ見えます
  • Normal Map: なしにするか、影響度を 0.01 など小さな値にするほど反射がハッキリ見えます

image.png

以上でいい感じに反射するようになると思います。

まるで年末の大掃除でピカピカに磨き上げられた綺麗なフローリング床みたいですね!

image.png

トラブルシューティング

記事の執筆中に遭遇したトラブルをまとめます。

ReflectionProbe に映らないオブジェクトがある

  • 対象の GameObject は static になっていますか?
  • ReflectionProbe の CullingMask は Everything になっていますか?

再生したら反射が消えた

staticバッチングが原因の可能性があります。床のMeshだけ static を OFF にしましょう。

Box Projection が有効にならない

Project Settings > Graphics > Reflection Probes Box Projection が ON になっていることを確認してください。

image.png

URPでBox Projection が有効にならない

URP Assetsに設定項目が移動しました。

image.png

まとめ

Unity標準ReflectionProbeのBox Projectionと標準シェーダーだけで、屋内シーンの反射による映り込みを大きく改善できました。

映り込みが綺麗にできると、光沢感やリッチ感を表現できますし、設定もそこまで手間がかからないので、コストパフォーマンスが高いと思います!

みなさんも是非 Box Projection を使いこなしてみてください!

26
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
19