技術

GPUを利用した任意形状の拡散面光源によるソフトシャドウ付き直接照明の計算

とりあえず実装した。
上が影なし、下が影あり。
(最初にこの記事をアップしたとき、影の計算を微妙に間違ってる部分があったので修正して画像もアップしなおした。)
GPU_no_shadow_1sec
GPU_soft_shadow_C1P1_32sec
今までtime.hのclock関数で処理時間を計測してたので、CPU時間を計測してたことになる。(Macなので。)
GPUを汎用計算に使うようになり、CPU時間の計測じゃまずいんじゃないかと思ったので、今回からtime関数による実時間の計測に切り替えた。
1秒単位でしか測れない点と、CPU時間は実時間より短めになってた点に注意が必要。

上の処理時間は1秒。下は32秒。
ソフトシャドウをつけるとかなり重くなる。
ソフトシャドウのために簡易的なGPUレイトレをやってるんだけど効率の悪い実装になってるためこれほど時間が掛かってる。
まぁGeForce 9400Mでこの速度なら、最新のハイエンドGPUでやったら1秒未満で計算出来たりするのかもしれないけど、効率が悪いというのは気になるので改良するか、別の方法を実装するかしたいと思う。

簡単に処理内容を説明すると以下のとおり。

まず影なしバージョンについて。
概念としては、面光源を多数の点光源を用いて近似する方法。

最初に、面光源を多数の点光源に分割する。
今回の場合は168個に分割した。というか自動で分割するようにしてて結果的にそうなった。
八分木を利用して点光源の分布が偏り過ぎないようにしている。

そしたら点光源の位置と法線を8個ずつGPUに送って普通にライティング計算をする。
点光源ひとつのエネルギーは面光源全体のエネルギー / 面光源の分割数として計算。
面光源の分割数 / 8 回描画処理が行われることになる。
各描画は加算ブレンドする。
これで完成。

次にソフトシャドウバージョンについて。
概念としては、影なしバージョンの結果に遮蔽率を掛ける方法。

最初に、影なしバージョンで計算。
そしたらポリゴンと点光源の組みあせわをすべてGPUに送って、光源がポリゴンによって遮蔽されてるか計算。
つまりポリゴン数 x 点光源数の描画処理が必要になるので効率が悪い。
実際は各々4つずつGPUに送って処理してるので、描画回数は16分の1となるが、まとめて処理する分描画処理そのものが重くなるので、劇的な効果があるわけじゃない。

で、遮蔽されたら1を、そうでなければ0を出力し、複数の描画を加算ブレンドし遮蔽回数を集計する。
最終的に遮蔽率を 遮蔽回数 / 点光源数 として計算。
遮蔽回数が0の部分は完全な日向、遮蔽回数が点光源数と等しい部分は完全な影、それ以外の部分は半影領域ということになる。
この遮蔽率を影なしバージョンの結果に掛けて完成。

多少工夫してるとはいえ、基本的にポリゴン数 x 点光源数( x ピクセル数)のレイ-ポリゴン交差判定が必要になるので効率が悪い。
各々が2倍になったら、処理時間は4倍になることになる。

また遮蔽をデジタルにカウントしてるので、半影領域の影の濃さが段階的になってるのが目立つ部分もある。
現在の方法でそれを目立たなくするには、点光源数を増やすのが実装するのが簡単というかパラメータ設定だけで実装する必要もないが、処理時間がかなり伸びることになる。
やはりこれでは効率が悪すぎるので別の方法を考えたい。

ちなみにポリゴンで近似された任意の形状の拡散面光源を扱えるのでこんなことも出来る。(それこそ平面だけじゃなくBlenderのスザンヌのような立体も光源として扱える)
GPU_soft_shadow_C1P1_807sec
ただ、光源の面積が広いと分割数も増加(この場合だと1500弱)するのでかなり重くなる。
これは807秒も掛かった。
しかも光源の面積が広いと半影領域が薄くなって見た目のインパクトに欠けるという。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です



※画像をクリックして別の画像を表示

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください