【Unity】【シェーダ】Reflection ProbeのBox Projectionの考え方

Reflection Probeの設定項目としてBox Projectionというチェックボックスがあります。
この記事ではBox Projectionの考え方について書きます。

基本的なキューブマッピングの知識が前提知識となります。

Box Projectionとは?

Box Projectionの概要については下記のReflection Probeの記事で紹介しています。

light11.hatenadiary.com

要するに、Reflection Probeを使ったときに近くにあるオブジェクトの映り込み方がおかしくなるのを補正する機能です。

f:id:halya_11:20180709004813p:plain

映り込みがおかしくなる原因

それではそもそもなぜ近くのオブジェクトの映り込みがおかしくなるのでしょうか?
これを考えるために、まずはキューブマップの中心位置における映り込みを考えます。

f:id:halya_11:20180709005017p:plain:w400

反射方向にオブジェクトがあるため、このオブジェクトが映り込む必要があります。

このケースでは単純に反射方向のキューブマップをサンプリングすれば、
そこにオブジェクトがレンダリングされているため問題なく映り込みます。

f:id:halya_11:20180709005223p:plain:w400

問題となるのは、中心からずれた位置における反射を考えるケースです。

f:id:halya_11:20180709005324p:plain:w400

このケースでは、単純に反射方向のキューブマップをサンプリングすると、
オブジェクトがレンダリングされている部分とまったく違う位置がサンプリングされてしまいます。

f:id:halya_11:20180709005458p:plain:w400

映り込みの補正

本来映り込むべきオブジェクトをサンプリングしたい場合には、中心からオブジェクトに向かうベクトルを得る必要があります。

f:id:halya_11:20180709005634p:plain:w400

キューブマップの中心座標とレンダリング対象の座標は既知なので、
反射方向とボックスの交点が求められれば下記のようにベクトルの足し算で必要なベクトルが求められます。

f:id:halya_11:20180709005751p:plain:w400

Box Projectionの実装

それでは上記の補正を行う関数を実装してみます。

float3 boxProjection(float3 normalizedDir, float3 worldPosition, float4 probePosition, float3 boxMin, float3 boxMax)
{
    // それぞれの面との距離を求める
    float magnitudeX = ((normalizedDir.x > 0 ? boxMax.x : boxMin.x) - worldPosition.x) / normalizedDir.x;
    float magnitudeY = ((normalizedDir.y > 0 ? boxMax.y : boxMin.y) - worldPosition.y) / normalizedDir.y;
    float magnitudeZ = ((normalizedDir.z > 0 ? boxMax.z : boxMin.z) - worldPosition.z) / normalizedDir.z;

    // 一番短い距離がBoxとの交点までの距離
    float magnitude = min(min(magnitudeX, magnitudeY), magnitudeZ);

    // プローブの中心から描画位置へのベクトル + 描画位置から交点へのベクトル = 補正された反射ベクトル
    return (worldPosition - probePosition) +normalizedDir * magnitude;
}

解説はコメントに書いた通りです。

実際にReflection Probeと組み合わせたものは下の記事で解説していますのでこちらを参照してください。

light11.hatenadiary.com

関連

light11.hatenadiary.com

light11.hatenadiary.com