2013年03月30日

環境マッピングについて

以前から環境マッピングの使い方がおかしい気がしていたので色々まとめてみました。
間違っていたら教えてください。

スカイドーム用のパノラマ画像は、左右が±180度、上下が±90度の範囲で映っている画像だと思います。
スカイドームでは、大きい球のモデルに対して、その内側にテクスチャとして貼り付けるものだと思います。

skydome_0001.png

この画像を球に貼り付けるためには、極座標系に変換する必要があります。
極座標系に関しては、Wikipediaを参考にしました[1]。
極座標系とは、座標を動径と偏角で表現したもので、球座標系⇔ワールド座標系の変換は以下の計算でできます。

skydome_0002.png

パノラマ画像の座標系と球座標系は、以下の図のような対応になります。

skydome_0003.png

以上の情報から、画像の座標系から極座標系の変換は、以下のようになります。

skydome_0004.png

この極座標系をワールド座標に変換するためには、最初に示した式を使います。

skydome_0005.png

今度は逆に、ワールド座標系からパノラマ画像の座標を求めたい場合は、これまでと逆の計算をすればよい、ということになります。

skydome_0006.png

スカイドームにテクスチャとして貼り付ける場合にはテクスチャ座標が必要ですので、上記の計算で球の頂点座標からパノラマ画像の座標を計算し、その座標をST座標に変換してやれば、スカイドーム用の球モデルを作成できる、というわけです。おそらく。

とりあえず一般的な使用方法?として、地面を仮定して、視線ベクトルの反射/屈折を計算した結果を以下に示します。
スカイドームにつきましては、[2]のussy様のHDR画像を使用させていただいております。



続いて、Image Based Lightingについてです。
これは、環境マッピングの画像を光源として利用しようというもので、これも使い方としていろいろあります。

大域照明を計算しようと思うと、周囲全てから当たる光を計算する必要がありますが、環境マップを光源として使用した場合も、半球状の光の反射方向全てを計算するのは計算時間的に難しいです。
そこで、16方向など、設定した数のみ計算する方法や、環境マップから光源を作成して、それを用いる手法などがあるようです。
今回は、パノラマ画像からk-means法でk個の光源を計算する方法[3]を試してみました。

パノラマ画像の各画素において、極座標系→ワールド座標系に変換して、そのワールド座標を元にk-means法で領域分割しました。
下の画像は、200個の光源を生成したもので、見やすいように画像をスムージングしています。

light200.png

この光源200個を平行光源と考えて、拡散反射成分(法線ベクトルと光源ベクトルの内積)と、鏡面反射成分(反射ベクトルと光源ベクトルの内積)を使って計算した場合、以下のような結果になりました。

skydome000_200.png

一応球→平面及び平面→球に当たった場合は加算しないようにしていますので、環境遮蔽のような効果はでていますが、何か変な線のような模様が出ておかしいです。
色の計算方法がおかしいのか、サンプル数(光源数)が少ないのか、どうなのでしょうね。

一応サンプル数を増やしたらどうなるのかの実験ということで、2500個の光源を生成してみました。

light2500.png

これを使って同じ方法で計算した結果、以下のようになりました。

skydome000_2500.bmp

一応滑らかになりましたが、計算時間がかかりすぎですね。

実行結果



次は球面調和関数を使う方法について試してみたいですが、理解できるかどうか微妙なところです。

[1] http://ja.wikipedia.org/wiki/極座標系
[2] http://www.nicovideo.jp/watch/sm10968092
[3] 倉地 紀子著, “CG Magic: レンダリング”, オーム社

web拍手 by FC2
posted by シンドラー at 18:18 | Comment(0) | TrackBack(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする

2013年03月21日

3次元の距離フィールドについて

気がついたら3月下旬になっていて困ったものです。

昔の記事で使った距離フィールドを、3次元で計算する方法についてです。
2次元の場合には、[1]に8SSEDTという方法の解説やソースコードがありわかりやすかったのですが、参考論文に高次元にも適用できます的なことは書かれているのですが具体的な方法がわかりませんでした。
どなたかわかりましたら教えてください。

文献[2]に、26近傍距離の3次元距離変換の方法について書かれていましたので、試してみました(実行結果(左))。
2次元の場合、左上原点として左、左上、上、右上の4つと比較して最小の距離+1に変換する順操作と、右下原点として右、左下、下、右下の4つと比較して最小の距離+1に変換する逆操作を行うことで距離変換ができます。
3次元の場合、上記に加えて一つ前のスライスの9近傍の計13個と比較していくと計算できるそうです。

文献[3]には、ユークリッド距離の3次元距離変換の方法について書かれていました。
ただ、この方法は、領域外の端も特徴点扱いされてしまうため、実行結果(右)のように端にも距離が出てしまっています。
“これが望ましくない場合は、わずかに修正を加えるだけで十分この問題を解決できる。”と書かれていたのですが、わずかな修正方法がわかりませんので、これもどなたかわかりましたら教えてください。

実行結果
slice0Z0133.png slice1Z0133.png

ねんどろいどみくさんのモデルをボクセル化して、真ん中辺りのスライスを表示した結果です。
赤と緑の線が内部と外部の境界線になっています。
ユークリッド距離の方が、計算時間はかかりますが滑らかな気がします。

ただ、1回ボクセル化してから距離計算をしているため、あまり精度がよくない気がします。
ポリゴンデータから距離フィールドを計算するような方法([4]等)をとった方が良いのかもしれません。

[1] http://www.codersnotes.com/notes/signed-distance-fields
[2] 村上伸一著, 3次元画像処理入門, 電機大出版局
[3] Gabriele Lohmann著, 3次元画像処理, ボーンデジタル
[4] http://http.developer.nvidia.com/GPUGems3/gpugems3_ch34.html
web拍手 by FC2
posted by シンドラー at 22:00 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする