GPUPPURでのレイトレーシング

 GPUPPURでのレイトレーシングについて説明しますが、絵とか図を使ったほうが分かりやすくなりそうだけど、大きな絵はアップロードできないのでがんばって文字だけで説明します。

 まずは、描画したい図形をPPUへ送ります。このときPhysXAPIを使って図形情報を送るのですがPhysX ver2.4で使えるらしい図形の種類は

  • Sphere(球)
  • Box(箱)
  • Capsule(カプセル、円柱の両端に半球をつけたような形)
  • Plane(平面)
  • Convex(凸面体)
  • Heightfield(高さmap、地形を表現するときによく使う図形)
  • Wheel(よく調べてないのですが、車のタイヤのようなものに使うようです。)
  • TriangleMesh(三角形メッシュ、三角形から成る任意の図形)

のようです。
TriangleMeshだけ使えば大抵の場合事足りるでしょうが、できるだけ他の図形を使ったほうが多分速いと思います。

 次に、出力結果の画像の各画素に対応するレイをCPU側で準備してPPUへ渡します。レイを数式で表すと
P(t)=vt+p
(tは0以上の数、vはレイの向きを表すベクトル、pはレイの始点を表すベクトル)
vとかpがどんな値になるかはカメラの向き、位置、視野角等によって決まります。
このvとpをレイの情報として、各画素数個用意してPPUへ送ります。

PPUで送られてきた図形とレイの交差判定処理を行い、各レイが始点から最も近い位置で交差した物体のID(図形を識別するためのユニークな番号)、交点の位置や交点での法線ベクトル等を求めます。得られたデータをCPUへ送ります。

PhysX ver2.4での物体とレイとの交差判定処理を行うAPIにはNxSceneクラスのraycastClosestShapeメンバ関数があります。ですがこの関数では一度に一つのレイしか扱うことができない上に、PPUで処理を行えないのでCPUで処理を行うようになっています。ですのであんまり速くはありません。
ですがAGEIA Developer Supportのページ
http://support.ageia.com
のKnowledge BaseのFeature Requests(アカウントを取ってログインしないと見れないようです)に
FR0011: HW Batched Raycastsというのがあって、
PPUにまとめて複数のレイを送ってまとめて交差判定を行って結果を返すという機能があります。
この機能がいつ使えるようになるかはわかりませんが、この機能が使えないとGPUPPURは高速にレイトレーシングを行うことができない、というかほとんどPPUを利用する意味が無くなってしまいます。

CPUでPPUから受け取った交差判定の結果を処理し、GPUで処理できるようなデータにします。
例えば、物体のIDをその物体のマテリアル情報へ変換するといったことや、GPUAPIに対応させるようにデータのメモリ上の位置を調整することなどです。
基本的に交差判定の結果データは出力画像の画素数個あり、そのすべてに対して処理を行います。

次にCPUで処理したデータをGPUへ送り、ライティング等の計算をして各画素の色を求めてディスプレイに表示します。
実際には処理したデータをテクスチャとして送った後に、画面全体に表示される大きさの矩形をレンダリングする命令を送って、
その矩形をラスタイズしピクセルシェーダ上で処理するときに、先ほど送ったテクスチャを参照してライティング等の計算を行い、求めた色を出力します。
このとき、矩形の4頂点に適当にuv座標を割り当てておく等して、ピクセルシェーダ上で今から画像のどの位置に出力するかを知っておきます。そうしておくとテクスチャのどの位置を参照すればよいかがわかります。
shader model3.0ぐらいではピクセルシェーダはdepth値を出力できるので、交点の座標からdepth値を求めて出力することができそうです。そうすると、レイトレーシングで表示された図形と通常のGPUの処理でラスタライズした図形を組み合わせて表示することができそうです。

以上がGPUPPURでレイトレーシングを行う方法です。
PPUとCPU、CPUとGPUでデータをやり取りする部分がボトルネックになりそうですが、
最初にPPUへ図形データを送る処理以外では、基本的に処理時間、必要なメモリの量は図形の量に関係なく一定の量となります。その代わり、出力画像の画素数に比例します。
図形の量に比例するのは最初の図形データを送るところだけですが、GPUPPURをgameなどで使う場合ではgame開始前に図形を送っておいて、後は図形の位置や向きだけを送ればそんなにボトルネックにはならないでしょう。
後、PPUでレイと図形の交差判定を行う処理ですが、PPUでは物体同士の交差判定を高速に行えるように空間分割等の工夫を行っているらしいです。ですのでPPUでのレイと図形の交差判定処理でも空間分割等の高速化技法を使い、処理時間がレイの数Nに対してO(log(N))となると思われます。

上記の方法で(もちろんPPU上ではまだ処理できないので代わりにNxScene::raycastClosestShape使ってますが)レイトレーシングを行うプログラムは一応もうできてます。
あんまり実装するのに時間が掛からなかったので、今年の正月頃に作ったのですがまだネット上に公開してません。
ソースコード尽きで公開してもいいんですが、どっかアップロードできるところないだろうか探し中。(面倒なのできちんと探してなかったり・・・)
これからGPUPPURをきちんとしたインターフェースが備わったライブラリにし、移植性や拡張性や高速性を高めていく予定です。

明日はGPUPPURでのラスタライズの話をする予定。