2012年

3月

10日

Bullet Physicsの勉強で愚痴をこぼす回

とりあえず色々と分かってきた。まだ参考文献の途中までしか進んでおらず分かってない部分も多々あるが、自分なりの解釈でメモしておく。

 ●世界の創造

 

まず物体を配置する世界、ワールドを作る(Physxはシーンというらしい)。この世界は「力学ワールド」というらしい。ここで重力や摩擦等を決める。

 

ワールドで衝突の判定を行うために「ディスパッチャ」、「ブロード・フェーズ」、「ソルバー」、「コリジョン コンフィグレーション」を設定する。わけの分からない単語が出てきたが、これらを理解するためにはBulletの衝突検知の流れについて理解する必要がある。

 

物理演算は一般的に階層化して行う。Bulletではそれを実装するために「ブロード・フェーズ」、「ナロー・フェーズ」という2つの段階での衝突判定を行っている。

 

「ブロードフェーズ」とは衝突検知をする物体をグループ分けをする処理。このフェーズである程度の階層化をしている。これにより衝突検知の検索回数が減る。

 

「ナロー・フェーズ」は実際に衝突検知アルゴリズムを適用する処理。グループ内での物体同士の衝突判定、衝突後の物体の位置・姿勢の設定をここで行う。ここで衝突物体の形状の組み合わせ毎にアルゴリズムを適用する必要がある(例:球・箱同士の衝突、球とはこの衝突)。この組み合わせを判断してそれぞれに適したアルゴリズムを適用するプログラムのことを「ディスパッチャ」という。

 

「コリジョン コンフィグレーション」は衝突検知のアルゴリズムとのこと。参考文献に今のところ説明が出ていないのだが、上記の説明に当てはめるとこれが「ナロー・フェーズ」なのだろうか?

 

「ソルバー」は参考文献には「専門性が強いのでここでは説明しない」とのこと・・・。Bulletの参考ソースを除いてみると「btSequentialImpulseConstraintSolver」というクラスを使用しており、コメントにはこう書いてあった。

 

the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)」

『デフォルトの強制解決者。並列処理については、異なる解決者を使用してもよい(エキストラ/BulletMultiThreadedを参照)』

 

・・よくわからん。何を強制的に解決するんだろう?

 

●物体の作成

上記の世界に物体をぶち込んでいく。まずは形状(シェイプ)を作成して形状の種類、大きさ等を設定する。そしてこの形状の情報を持った剛体オブジェクトを作成してワールドに追加することで衝突判定が可能になる。剛体には慣性テンソル、動き等を設定する。

 

Bulletには基本シェイプで「球」、「箱」、「カプセル」、「円筒」等が用意されている。ちなみにPhysxの基本シェイプに「円筒」は含まれていないらしい。

 

●シミュレーション

ワールドの時間を進めて、その時間にどのように物体が動き衝突するのかを検証する。実際はワールドのインスタンスメソッド「stepSimulation」を呼んで時間を進めるだけでそのステップの物理演算をを全て行ってくれる。全く便利な関数だ。

 

まぁ便利な反面、内部でどのような処理がされているのかわからない。幸いオープンソースだから処理の内容を見れるのは助かります。今度コードを覗いてみよう。

今回のメインのお話。というかちょっとがっかりしたこと。

 

サンプルのあるプログラムを動かしてみた。内容は「物体を飛ばして着地するまでの時間の計測」と「FPSの計測」という簡単なプログラム。シミュレートの経過時間はリアルタイムで進めた。

 

以下はそのプログラムを起動したときの様子。一番小さな人が上空へ飛んで着地する一連が見れると思う。

このプログラムの計測結果はこのようになりました。

左上から順に「理論上の着地時間」、「実際の着地時間」、「理論上の最高到達点」、「実際の最高到達点」、「FPS」である。

 

問題はFPSの値。すさまじく遅い。

モデルは頂点数15,806個、ポリゴン数5,270枚で5体表示しているとはいえあまりにも遅い。試しに物理演算無しでモデルだけ5体表示してみると40~44FPSになった。つまり5体の物理演算だけで演算だけでFPSが20ほど減ったことになる。

 

参考文献の著者の場合このプログラムは「45FPS」になったらしいです。CPUの処理能力が低すぎる・・・

 

自分のPCのCPUの低スペックさにがっかりしつつもあることを思い出した。Bullet PhysicsはGPGPUに対応しているらしく、物理演算をCPUではなくGPUで行うことが出来るとか。

 

描画にはDirectXを使っているのですが、調べてみるとDirectXにはWindowsでGPGPUをサポートする「DirectCompute」という機能があるらしい。

 

「これで処理を高速化出来るのでは?」と期待しつつ実装方法を調べてみると・・・

・DirectComputeの言語はHLSL ・・・ 特に問題はない

・GPGPUに対応したGPUが必要 ・・・ GPUはATI Radeon これも問題ない

・DirectXのバージョンは10~11(Windows Vista、Windows 7)

 

・・・・・・え?(´Д`;)

これで今日のやる気がすっ飛んだ。XPやDirectX9はもう時代遅れなのだろうか・・・?OSの壁は越えられないなぁ。Windows7の開発環境がほしいです。

 

OpenGL+XPでGPGPU出来るかどうか調べてみて、可能ならOpenGLで描画しようかな。

 

あともう一つ気になる点。

サンプルのプログラム実行するとメモリリークが出るんだけど・・・

このプログッラム、もう少しどうにかならなかったのかな?

 

というわけで今回は愚痴って終わりです。

追記:

すみません。GPGPUについてですが色々と勘違いをしていたようです。見当違いの記事を書いてしまっていたようです・・・調べなおしてまとめてみました。

 

そもそもGPGPUとは?

General purpose compting on GPU:GPUの多目的コンピューティング。

本来グラフィックス処理に利用するGPUの高度な演算機能をグラフィックス以外のことに活用しよう!という技術のこと。

 

CPUはシングルスレッドの実行性能が求められるのでコアが大きくなってしまい、一つのCPUに搭載できるコア数は限られてくる。それに対してGPUは1コアの計算処理能力はあまり高くは無いが、コア自体がコンパクトなのでそれを数十~100以上を並列で動かすことでCPUを上回る計算性能を発揮する。

 

つまりグラフィックス以外の並列処理に向いた演算処理をすることでその力を大いに奮ってくれるわけです。このGPGPUを使うことで性能が上がる処理に「動画のエンコード」、「音声編集」、「レイトレーシング」、そして「物理演算」等があります。

 

前回「DirectComputeはDirectX11なのでXPでは使えない」「OpnGLで出来るかどうか」とか書いていましたが、そもそも描画目的で使うわけではないので描画ライブラリは何を使っても関係ないんです。肝心なのは「Bullet Physicsが並列処理に対応しているか」という点です。

 

Bullet Physicsの日本語マニュアルに並列演算についてのページがありましたので引用してきました。

15. 並列処理: SPU, CUDA, OpenCL


Cell SPU / SPURS の最適化

Bullet衝突判定および物理演算は、Cell SPUに最適化されています。すなわち、衝突判定コードは複数のSPUプロセッサで並列処理できるように、また衝突判定のコードやデータはSPUのローカ ル・ストア・サイズである256kbに収まるように書かれています。これを使う場合は、SPUに処理させる特別な衝突ディスパッチャ (SpuGatheringCollisionDispatcher)を使用してください。Bullet/src /BulletMultiThreadedにこれが実装されています。

BulletのPlaystation3に最適化されたバージョンについては、PS3 DevnetのSonyデベロッパーサポートにお問い合わせください。

 

統合マルチスレッド

SPU並列処理に使った方法を、マルチコアプロセッサなど他のマルチスレッド環境に利用することができます。すなわち、マルチコアプロセッサを 利用して、Windows上でSPUコードをデバッグすることができます。SPUを使用しないマルチスレッド環境では、memcpyによるDMA転送を仮 想化しており、各スレッドはメモリに配置された256kbの'ローカルストア'を利用することになります。

 

Win32 Thread、pthread、sequential threadのサポート

Win32のthread、pthread、sequential threadを使って、SPUタスクが実行可能です。デモの中に、この準備作業が示されています。Demos/ConcaveDemo と ConvexDecompositionDemo にある#define USE_PARALLEL_DISPATCHERをご覧ください。

 

IBM Cell SDK 3.1, libspe2 SPU への最適化

IBMは、CellブレードやPS3 Linux platformのlibspe2を使ってSPUにアクセスするCell SDKを提供しています。libspe2スレッドは、SpuLibspe2Supportにより利用可能です。

libspe2バージョンをコンパイルする場合は、まずBullet/src/ibmsdkのmakeを実行してください。
その後、Bullet/src/BulletMultiThreadedディレクトリにてmake –f Makefile.original spu ppuを実行し、更にBullet/Demos/CellSpuDemo/ibmsdkディレクトリのmakeを実行してください。

 

btCudaBroadphase

現在、我々は物理パイプラインの一部のパフォーマンスを上げるために、CUDAやOpenCLの研究と開発を行っています。Extras/CUDA と Extras/CDTestFramework にて、この初期段階の研究内容を見ることができます。

Bullet 2.76の頃のものなので「CUDEやOpenCLの研究と開発を行っている」とありますが、現在リリースされているBullet 2.80を見てみるとのOpenCLで開発したBulletライブラリがありました。既に形になっているようです。

 

このライブラリを使うことでGPGPUで物理演算が出来るようになるのでしょうか?とりあえず試してみます。というわけで今回はココまで。