C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

After care: C++ Advent Calendar 2012 / day 4th : Native-client vs. HTML5 ; C++ in the web-client-world!

先日のC++ Advent Calendar 2012 / day 4th : Native-client vs. HTML5 ; C++ in the web-client-world! - C++ ときどき ごはん、わりとてぃーぶれいく☆の続き、その1です。

ちょっとだけリファクタリングしたり、C++とJSのインターフェース部分のやっつけ感をどうにかするなどしました。

f:id:USAGI-WRP:20121207194935p:plain

特に意図して居ませんでしたが、どうやらSCOREも上昇した様です^-^
(粒子群や画素群の更新がリファクタリングに伴い少々コンパクト&スマートになった影響かな。)

主な変更点
  • パーティクルシステムの定義をnative-clientのインスタンス定義用のinstance.hxxからparticle_system.hxxへ分離
  • JS-->C++のインターフェースをやっつけ文字列コマンドからJSONに変更
  • particle_system内のparticle及びpixelの状態更新をparticle/pixelそれぞれの内部ではなく、particle_systemから行う様に変更。particle/pixelはparticle_systemに対しfriend。
  • スクリーンと描画空間の分解能の任意設定を実装。一部マジックナンバーとなっていた分解能に関する決め打ちの値を任意に設定可能になりました。
    • JS側にdebug_command.change_resolutionなる関数を実装したので、ブラウザーの開発者ツールのJSコンソールから debug_command.change_resolution(640,480,64,48) を評価すると、スクリーン分解能VGA、画素分解能64x48(画素サイズ10x10)に切り替えるなど可能になりました。

この後は

次はパーティクルシステムの効率化かな。

ちなみに、実は当初HTML5(pure)版を書く段階で非常に重いベンチマークになる事は想像できますので、「全ての画素が全ての粒子からの影響を計算する」のではなく、「粒子から一定距離の画素にのみ粒子の影響を計算する」なる実装にしていました。

例えば、前者の場合は、ある粒子が(x,y)に存在した時、画素空間の分解能が160x90であれば14.4k個の画素に対して粒子からの距離に基づいた色(光)の影響具合を計算する事になりますが、後者の場合には粒子の半径rまたはrに影響量を増減する調整用の定数を掛けたr'を用意し、仮に之が40画素分程度の距離であれば、πr'r'=3.14…×40×40≈5,027個の画素だけに粒子の影響を計算すれば良い事になり、負荷を大きく下げられます。

実際には、画素群は特別なデータ構造を持たせない限り、描画系APIとの整合性もあり、通常は離散的な2次元のユークリッド空間(X軸とY軸に四角い升目状に考える)で管理していますから、粒子の座標の周囲を円形に列挙する事は少し難しく、先ずは粒子の影響範囲が外接する矩形領域を切り出し、列挙コストと画素の処理コストを天秤に掛けて、画素と粒子の距離を計算するか、或いは綺麗な円形ではなく矩形領域をそのまま粒子の影響範囲の計算対象として処理を行います。

しかし、今回実装したパーティクルシステムでは、結局は画素の光り具合の決定に全ての粒子との、いわば総当りの計算を行なっています。光り具合のモデルを、{(I)ntensity}={c_(l)uminance}/({(d)istance}+1)、但しI:光りの強さ、l:光り具合調整用の定数、d:画素に影響を及ぼそうとする粒子までの距離、としつつ、lを大きめにし、光り溢れつつも飛び回る粒子感もある眩しくて綺麗な…とかやっているうちに、ベンチマークだし総当りで計算した方が綺麗な絵が簡単に出るし良いかな〜と、そんなノリで総当りの実装になっています^^;

と、まあそれはさておき、粒子から画素群の列挙であれば上述の通りで、ゆっくり整理して考えれば矩形領域の画素群の切り抜きは簡単に想像できますね。では逆ならばどうでしょう?つまり、ある画素が主体となり、周辺にある粒子を列挙し、それらからの影響を計算するとしたなら。

粒子群は勿論動きにその粒子群の存在する世界の物理法則は適用できますから、実際完全に予測したり、事前に計算しておく事も可能です。乱暴に片っ端から事前計算してしまってデータベース化しておくか、或いはオイラー法よりも高度な精密な計算を行い高精度に予測する必要がある、でしょうか?

列挙は可能だがそれぞれの座標が予測できない粒子群についてある座標の近くに居る粒子を効率的に抽出できる様に工夫したデータ構造があります。代表例は任意の矩形領域に粒子群を分割して記憶する事をベースとし、矩形領域からのピックアップを得意としたRectangler-tree、またその円バージョンの派生データ構造、或いは対象空間を2分割を繰り返してそれぞれに含まれる粒子群を記憶したり、その分割比率を任意にできる様にしたりするkd-tree系のデータ構造など、モデルに応じて粒子群のデータ構造を最適化しておく方法もあります。

実はこの後、このベンチマーク用のパーティクルシステムをどのように効率化してこのシリーズを進め様かはまだ考えていません^^; もちろん、マルチスレッディングやSIMD(NaClで動くかなぁ…)周りなどの実用的な力技やシェーダーを使ってしまうチートも含め、もうちょっと年内にこの記事の続きも書きたいと思っています。

ではみなさん、良いお正月を〜^^(ぉ