Ray-Based TemporalReprojection for ScreenSpaceReflection

概要

 Stochastic Screen-Space Reflectionsでは、サンプル数を増やすためにTemporalReprojectionが使われています。
しかし普通のTemporalReprojectionを使うと、平行移動時に歪みが発生してしまうので、特別なReprojectionをしているようです。
 この資料の説明ではDepthの代わりにレイを用いるとありますが、詳しく書いていなかったので少し考えてみました。

用語

F0:1フレーム前
F1:現在のフレーム

P1:現在処理しているピクセルの画面座標
P0:P1の1フレーム前での画面座標

PW:現在処理しているピクセルのワールド座標
Normal:現在処理しているピクセルのワールド法線

M0:1フレーム前のViewProjection行列
M1:現在のViewProjection行列

C0:1フレーム前のワールドカメラ位置
C1:現在のワールドカメラ位置

T0:1フレーム前の結果(テクスチャ)
Depth:現在処理しているピクセルの深度値

COLOR0:1フレーム前の色情報(←最終的に求めたいモノ)
COLOR1:現在の色情報

Ray0:F0で反射ベクトルが衝突した位置
Ray1:F1で反射ベクトルが衝突した位置

通常のTemporal Reprojection

 まず普通のTemporal Reprojectionをおさらいします。

  1. P1とDepthを使ってM1の逆行列でワールド座標PWを求める
  2. PWをM0で再投影(Reprojection)し、P0を求める
  3. P0をuv座標として用い、T0からCOLOR0を取得する
  4. COLOR1と混ぜて、サンプル数を増やす

スクリーンスペースリフレクション(SSR)で使う場合の問題

 SSAOなど、同じ場所ならどの角度から見ても同じ結果になるという場合(見る角度に依存しない = view-independent)は問題ありません。

 しかしSSRでレイマーチする反射ベクトルは、見る角度によって変わってしまうので、結果のCOLOR0とCOLOR1は違う場所(Ray0とRay1)から取得してきていることになり、前述の歪みの問題が発生します。(下図のTOPを参照)
 Ray0とRay1のPWからの距離が長ければ長いほどズレは大きくなり、歪みが目立ちます。近距離の映り込みはあまり歪まず、遠距離が映り込む場合大きく歪む原因はこれです。

解決法

 ワールド位置のPWはもはや使い物になりません。
COLOR0とCOLOR1を結びつけているのはPWではなく、Ray1なのです。

F0のとき、C0を通ってPW'に反射してRay1に到達する、そのような地点PW'を求め、
その地点を再投影してCOLOR0を取得します。

色々考えましたが、思いついたもので一番簡単な手順は……

  1. PWとNormalからワールド座標平面dを定義する
  2. 平面dに対しC0の面対称であるC0'を求める
  3. C0'からRay1へ向かう線と、平面dとの交差がPW'となる(平面反射[Planar Reflection]と同じ)


下の図を見てください。

f:id:IARIKE:20151010105535p:plain
f:id:IARIKE:20151010105540p:plain


 求めたPW'を再投影すれば、そこには偶然Ray1付近を取得した色情報COLOR0があるはずなので、
ありがたくサンプルとして活用します。

 前提としてPWとPW'は同一平面上(→同一の法線)という仮定が入りますが、
歪みが目立つのは特に平面においてなので、問題ないでしょう。
(もし法線が違ったり、ラフネスが違っている場合などはサンプルとして使わなければ良いだけです)

C0からC0'に移動するときの(平面反射の)方法は
Planar Reflections (FIXED) - Graphics Programming and Theory - GameDev.netで色々議論されているうちの、
11.1.2 Planar Reflectorsの行列を使えばよさそうです。

平面と線の交差は
t-pot『Ray Tracing : Intersection with triangle』
に式があります。


どうでもいいけど、最近全然入門じゃないですね…