水鳥コンビナート

CGとかUnityとか

Separable Subsurface Scattering

Separable Subsurface Scattering

vimeo.com

EGSR 2015 の論文。 サブサーフェススキャッタリング (SSS) を行う際、 表面下拡散のカーネルやら入射光やらが 軸ごとの関数に可分 (Separable) であるという仮定を置くと 高速に計算できてリアルタイムでも SSS できちゃうねという手法。 略称は SSSS でなんだかすごそうな感じがする。

サブサーフェススキャッタリングしたい

SSS というものを真面目に計算しようとした場合、 物体内に入射した光が表面化で何度も散乱して出てきてカメラに届く光路を 計算しなければならないので大変重くとてもリアルタイムには計算できない。 オフラインレンダリングでも割としたくない。

この計算の近似には手法が色々とあるが、 その一つに拡散カーネル  R_d(x,y) での畳込みによる手法がある。 ある物質の拡散カーネル  R_d(x,y) は、xy 平面を表面として z <= 0 の空間に均一にその物質が充填されている場合に、 原点から垂直に入射した光と点 (x,y,0) から出てくる光の比を示す。 そしてこのカーネルと入射光  E(x,y) との二次元畳み込み積分を行ってやると、ある点から出てくる光  M_e(x,y) が計算できるよね、ということである。 (ただし、物質の厚さが無限大であるのを仮定しているので実際の物体に対してこれを計算すると透過光の影響は無視される。 また、入射光の方向も考慮しない。)

可分性による畳み込み高速化

しかし、こうした二次元畳み込みの計算は非常に重くリアルタイム向きではない。 畳み込み積分のサンプリング点が縦横  M 個ずつだとすると、 一点についての畳み込みの計算量は  O(M^2) になる。

この畳込みの計算量を減らすために、拡散カーネル  R_d(x,y) が可分な関数  N 個の線形和  A(x,y) で表せるという仮定を置く。 可分とは、x についての関数と y についての関数の積で表せるということであり、 つまりこのとき  R_d(x,y) \approx A(x,y) = \sum_i^N a_i(x)a_i(y) となる。 拡散カーネルは放射状に対称な形をしているので、ここで x 方向と y 方向の関数は同じになるのに注意。 こうした可分な関数として典型的に使用されるのはガウス関数である。

こうすることにより、二次元の畳み込みは x 方向の畳み込みと y 方向の畳み込み計算に分解することができ (式は省略)、 計算量は N 個の一次元畳み込みを x, y それぞれに行うので  O(2NM) となりさっきよりは断然マシになる。 実際画像処理ソフトとかでも二次元のガウスぼかしをする際には横にボカしてから縦にボカすような実装にしていたりする。

もっと畳み込み高速化 やり方1:特異値分解による低ランク近似

で、もう既に二回ぐらい近似したり限定的な仮定置いたりしたが、 まだリアルタイム用途には重い。 具体的に言うと  N=1 でいい感じに近似してやりたい。 そこで更に工夫をする。

拡散カーネルが可分かつ放射状に対称であるという仮定のもと、 拡散カーネルを離散化して行列にしてやった上で 特異値分解を行うと以下のような形になる。

f:id:mizuooon:20171212193729p:plain

これは例えば拡散カーネルが二次元ガウス関数の線形和だったとすると、 一次元拡散カーネルがそれぞれ異なる分散の一次元ガウス関数を表し、 特異値  \sigma_1, \sigma_2, ... は線形和の係数を表す。 これは本質的には主成分分析であり、 低次の特異値と一次元カーネルのみを使えばもとの二次元カーネルが近似できる (低ランク近似)。

ということでこれで近似した二次元拡散カーネルを使うことで、  N を減らして計算量も減らしちゃおうということである。  N=1 としてやればめでたく計算量は  O(2M) まで落ちる。

もっと畳み込み高速化 やり方2:積分済み可分カーネル

しかし、低ランク近似による方法で  N=1 にしてやると十分な速度で動作はするようになるが、 カーネルのエネルギーロスが大きく正規化したとしても見た目が良くないという問題がある。

そこで、畳み込み高速化を行う方法として、 積分済み可分カーネルを使う方法が提案されている。

これは、拡散カーネルの可分性に加えて、 入射光  E(x,y) の加算についての可分性を仮定することで 拡散カーネル再現のロスをゼロにしたまま計算量を  O(2M) にしちゃおうという方法である。 この加算についての可分性というのは、関数が x, y についての関数の和で表せるということであり、 つまりは  E(x,y) = E_1(x) + E_2(y) ということである。

式変形とかは論文中の Eq.4 そのままなので省略するが、 こうした仮定を置くと拡散カーネルについての x 方向、y 方向に分解した積分が事前計算できるようになるため、 ランタイムの計算が一次元の畳み込み 2 個で済むようになる。

入射光が加算についての可分である、という仮定については、 可分じゃない場合についてもそれなりによく見えるし、 現実の光は大体可分なのでまあいいんじゃないかなという感じらしい。

別のアプローチ:アーティストにやさしいモデル

リアルタイムに SSS やりたいよねっていう目的は上記のでこなしたけれども、 上記の手法ではアーティストが望んだ見た目を作るのが難しいというのが工業レベルでの問題になる。 (望んだ見た目になるように拡散カーネルを決めてねって言われてもどうしようもない。)

そこで更にアーティストがパラメータをいじりやすいモデルが提案されており、 それは一次元カーネルを近距離と遠距離についての 2 つのガウス分布の重み付き和で表すものになっている。 (二次元カーネルを二次元ガウス分布の線形和で表すのとは違う。)

正直モデルだけ見てもわからないが直感的で扱いやすいらしい。

その他細かいテクニック

  • 入射光の幅が拡散カーネルの幅より小さい場合とかには、 拡散が放射状でなく縦横方向に強くなっているのが見えてしまう。 これを防ぐため、拡散時の軸の方向をランダムに回転させた。
  • Kernel footprint and evaluation ← よくわからなかった
  • 一次元の畳み込み積分時、カーネルの中心部の方がエネルギー高い傾向を利用して インポータンスサンプリングを用いて計算した。

結果とか

二次元拡散カーネルガウス分布の線形和で表す既存手法と、 今回提案されている、 特異値分解モデル、積分済みカーネルモデル、アーティストフレンドリーモデルが比較されているが、 積分済みカーネルモデルが高速かつ精度の高い結果になっており一番いい感じらしい。