技術

フォトンベイカー(仮)進捗その6

シーンにばら蒔いたフォトンを元にシーン内のある点の放射輝度推定を行うとき、レイトレースがよく用いられると思う。
カメラからスクリーンの画素の方向へレイを飛ばし、そのレイがぶつかった物体表面に関して放射輝度推定を行うのだ。

レンダラーを作ってるのなら、ひねくれた事を考えなくても普通にレイトレースすればいいんだが、今作ってるのはテクスチャベイカーである。

普通にカメラからレイを飛ばしても、画面の外側や他の物体に遮蔽されてる部分の色データは計算出来ない。
いやまぁ工夫すれば出来ないこともない。
例えば、シーン全体を含むようカメラ位置を調節し、レイを飛ばし、最初は1回目に物体にぶつかった部分の色を計算、次は1回透過させて2回目に物体にぶつかった部分の色を計算、なんてことを繰り返せば理論的にはシーンの全てのポリゴンの全ての点の色が計算出来るはず。

しかし、視線をかすめるような角度のポリゴンの色を計算するときに誤差が出そうだ。
まぁそれさえも回避する方法は思い浮かぶ。
例えば、ポリゴンの法線と視線の角度がある一定以上ある面についてはとりあえず放置して、カメラの位置・角度を何回も変えながら全ての面の計算が完了するまで続ける方法とか。

しかしとてもめんどくさそうだ。

他にもっといい方法がある。
ポリゴンを細分化して、そのポリゴン内のあらゆる点において色の計算を行い、その地点のuv座標からいちばん近いテクセルを割り出し、そのテクセル(またはそのテクセルの周囲)に計算した色を書きこむという処理をポリゴン単位で行えばいい。

しかしこの方法でさえ、最初に挙げた方法より圧倒的にマシに思えるけど、それでもなんだか筋が悪い感じがする。

できれば精度やシンプルさの観点から、テクスチャ空間で、テクセル単位(もしくはサブテクセル単位)で処理したい。
これができれば例えばテクスチャサイズが512×512の場合、512×512回のループで計算が完了する。

ある点とその部分の法線が分かってれば放射輝度推定は出来る。
つまりこの方法を実現するためには、あるテクセルが三次元空間上のどの位置に対応し、どういう法線を持ってるかについて知る事が出来るデータ構造が必要。

このデータ構造は簡単に作れる。

ポリゴンを元のテクスチャと同じサイズのテクスチャ空間でラスタライズすればいい。
ただしラスタライズで出力する値は、色ではなく、位置情報と法線情報である。

ラスタライズ…そう聞くとなんだか自力で実装してみたかったりそうでなかったり複雑な心境だけど、そんな事をしなくてもラスタライズを超得意とするアイツがすぐそばにいる。

そうGPUである。

頂点シェーダで頂点のuv値を座標として利用し、あとはフラグメントシェーダで位置と法線を書き込むだけで実現できる。
具体的には、位置用のデータ(ポジションマップ)の保管場所として浮動小数点RGBテクスチャを、法線用のデータ(法線マップ)の保管場所として24bitRGBテクスチャを使い、MRTで一気に書きだせば良いだけ。
(まぁMRTは必須じゃないけど使った方が楽だと思う。あと2つのデータを圧縮してまとめれば半精度浮動小数点RGBAテクスチャとかでも行けるかもしれないけど、そこまで切り詰めるつもりは今のところない。)

もったいぶった書き方しちゃったけど、遅延シェーディングとかで普通に用いられる考えかただと思う。

ということで、GPUでポジションマップとノーマルマップを生成するコードを実装したので、その結果を。
スクリーンショット 2013-04-08 20.18.27
これは3枚のテクスチャを今までの画面に表示したもの。

左上のテクスチャは、元のテクスチャ。(blenderのライトマップパック機能を利用してベイクしたシーン全体のテクスチャデータ)
左下はポジションマップ。(画面に表示するにあたってノーマライズして0.0〜1.0になるようスケールしてる)
右下はノーマルマップ。(今回のシーンはソリッド面だけで構成されてるので、面内での法線の変化がなく色変化がない)

あとはさらにベイク用のテクスチャを用意して、ポジションマップとノーマルマップとフォトンマップを参照しながら色を計算すれば、一応目的は達成されるはず。

コメントを残す

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



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

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