椿の日記

たぶんプログラムの話をします

Frequency Domain Normal Map Filtering続き^3

セクション7で出てきた次の式(16)、


r = A(\kappa) \mu
A(\kappa) = \coth(\kappa) - \frac{1}{\kappa}

の出所は、これはClustering on the Unit Hypersphere using von Mises-Fisher DistributionsのAppendixに乗っていました。導出の詳細は論文を参照するとして、von Mises-Fisher分布関数のパラメータκとμをEMアルゴリズムで法線データから推定する際に出てくる項であるようでした。特に3次元の場合は双曲線関数を利用して上記式のように単純な形で書けるようです。

Frequency Domain Normal Map Filtering続きの続き

論文のセクション8にも意味が分からなかった部分があったのですが、解決したので覚書しておきます。

問題を要約すると、入射方向ωi、出射方向ωo、そのハーフ角ωhについて、

\displaystyle \int_{S^2} L(\omega_i) f(\omega_h(\omega_i,\omega_o)) d\omega_i = \int_{S^2} L(\omega_i(\omega_h,\omega_o)) f(\omega_h) 4(\omega_h \cdot \omega_i) d\omega_h

が成り立つ、というものです。通常の反射の積分は入射方向で球面上を積分しますが、Blinn-PhongとかTorrance-Sparrowなどではハーフ角が主役になり、その積分変数に変換したのが上記式です。

このように変換しておくと、予めLと4(ωi・ωh)の積についてωhで球面調和展開した形式を用意しておけば、照明計算を畳み込みによってただの線形結合で表せるようになります(但し、Lはωiとωoにも依存しているため、ωiとωoに関して離散化したテーブルを用意し、それを補間する必要があります)。

で、このとき置換積分に伴って現れる 4(ωi・ωh) は一体どこからくるねん!という話なのですが、Physically Based Rendering From Theory to Implementationに解法が載っていました。以下は、ほぼそのまんま本の内容です。

まず、ωoを基準とする座標系に移し変えて考えます。例えばωiとωoを含む平面を考えると次のような図を考えられます。

f:id:tbk:20121208030556p:plain

ここでθiはωiとωoの間の角度、θhはωhとωoの間の角度です。ここで立体角ωiとωhは単位球上の面積を表し、その微小な変動量は次のように求まります。

\displaystyle d\omega_i=\sin \theta_i d\theta_i \cdot d\phi_i
\displaystyle d\omega_h=\sin \theta_h d\theta_h \cdot d\phi_h
従って、

\displaystyle \frac{d\omega_i}{d\omega_h} = \frac{\sin\theta_i \cdot d\theta_i d\phi_i}{\sin\theta_h \cdot d\theta_h d\phi_h}
ωhはωiとωoのハーフ角なのでθi=2θhです。また、ωoを基準とする座標系においてはφi=φhが成立しています。従って、

\displaystyle \frac{d\omega_i}{d\omega_h} = \frac{\sin2\theta_h \cdot 2d\theta_h \phi_h}{\sin\theta_h \cdot d\theta_h d\phi_h}

sin2θを倍角の公式で展開し、微少量dθh dφhを消去すると、

\displaystyle \frac{d\omega_i}{d\omega_h} = \frac{4\sin\theta_h\cos\theta_h}{\sin\theta_h} = 4\cos \theta_h = 4(\omega_i \cdot \omega_h)

これがωiからωhへ積分変数変換したときに発生します。

Frequency Domain Normal Map Filtering続き

この論文も後半でいくつか分からない部分がありました。

論文の後半は、NDFを近似するにあたってvMF(von Mises-Fisher)分布を用いています。vMFは球面上の1つの突起を表現していて、方向、幅、振幅の3つのパラメータで表されます。複数の突起を扱うには、その線形結合であるmovMF(mixture of von Mises-Fisher)分布を利用します。で、これらの複数の突起はテクスチャで保存されます。N個の突起を表すにはN枚のテクスチャが必要になります。

レンダリングのときは突起のパラメータをトライリニアフィルタでフェッチするのですが、このとき同じテクスチャの中では近傍テクセルに似たような突起が並んでいなければなりません。例えば、テクスチャ1の座標tには突起A、座標sには突起Bがあって、テクスチャ2の座標tには突起B、座標sには突起Aがあるとします。それぞれの座標tとsでは結合すると同じmovMFですが、各テクスチャ内で補間すると、突起AとBで補間されてしまいます。なので突起を入れ替えておく必要があります。で、これを防ぐためにmovMFの解析のときに整列するよう細工するようなのですが、どうもここがよく理解できませんでした…。Appendixに解説があったんだけど、これが全くイミフ。

それからセクション7.1の式(16)が完全に意味不明でした。一体この式はどこからくるのかなあ。

Frequency Domain Normal Map Filteringを読了

Frequency Domain Normal Map Filteringを読みました。法線マップのフィルタリングに関する論文で、法線マップを単純にミップマップ化すると法線が平均化されて想定外の方向を向いてしまい、シェーディング結果が変わってしまう
問題に対してどのように対処するのか、ということを解説してるみたいです。

これは例えば「VVVVVVVVVVV」というような形状のギザギザだけどスペキュラの指数係数が大きな板を考えると分かりやすいです。このような凹凸を単に法線マップ化して線形フィルタを使うと、法線は平均化されて板に対して垂直に向いてしまいます。スペキュラ反射色は法線方向に依存してしまうので、スペキュラハイライトが全然違う結果になることが容易に想像できます。

で、この論文の手法は、まず法線マップを法線分布関数(NDF)と呼ばれるデルタ分布関数で表現し、このNDFを球面調和関数(SH)展開してその係数を保存します。法線はSH係数から復元することができます。そしてこの係数は単純に線形補間することができ、線形フィルタを利用しても上記のようなアーティファクトが出ないということであるようです。

ただ、SHはデルタ関数分布の近似としては余り嬉しい形状ではありません。このためこの手法ではNDFをSHとは別に放射基底関数(Radial Basis Function)で近似するようです。このNDFの近似の問題に限っては単純なSHよりも適していて、これを使うことでより効率的にNDFを保存できる、とのこと。

…というわけで一通り読んだのですが、結構使える範囲が限られる気はします…(鏡面反射するようなマテリアルで、法線方向が急激に変わるようなタイプの法線マップだといいのかな?)

SparseVoxelOctreeの記事を読んだ続き

Interactive Indirect Illumination Using Voxel Cone Tracing について、ようやく大体のことを理解しました。細かいところで色々と分からない部分が出てきそうなので、理解を深めるために一度実装してみようかな。
ただ、現時点でSection 7のVoxel Shadingのところがよくわかっていません。Voxelにライトを当てたときにどのような色を反射するのかを解説している箇所です。Sparse Voxel Octreeの作成の過程でBRDF(のガウス分布関数による近似)とNDF(のガウス分布関数による近似)をボクセルに埋め込んでいくのですが、結局このNDFとBRDF(と光源情報)を利用してどのようにボクセルをシェーディングするのかは他の論文に丸投げしてあるようです。
これは単なるシェーディングの話なので、まずこちらの話を詰めておかないとならなさそうです。

SparseVoxelOctreeの記事を読む

急にUnrealEngine4で実装されているといわれるGIアルゴリズムについて調べたくなったので、関連する論文とか資料を読んでいます。SparseVoxelOctreeを利用したこのアルゴリズムは、光源方向からのフォトンの照射とOctreeへの格納、それから視点方向からの三角形ラスタライズからのコーントレーシングを合わせて2-bounceを実現しているっていうアルゴリズムなんでしょうか。細かいところはよく分からないんですが、今までのリアルタイム系アルゴリズムと比較すると、かなりフォトンマッピングに近い考え方に見えます。細かいところをきちんと調べて実装してみたいところ。

最長増加部分列がイマイチ分からない

蟻本を少しずつ進めています。p.63~p.65の最長増加部分列の説明なのですが、自分にはどうも自明には思えなくて、そこで少し停止しています。dpは単調増加であるとか、更新できる要素は高々1個しかないとか、そこらへんが解説なしに進んでいってしまうので、ハテ?という状態。かといって証明しようにもどうしたらよいか分からんので困った感じです。それは正しいものと受け入れて次に進んでしまえば速いのですが、なんかスッキリしない感じ。うーんどうしたものか。