とはいえ、DirectCompute(CS:ComputeShader)への実装にあたっては、まったくの新規開発要素となったために、専用のソフトウェアを書き下ろすことになった。

まず、波動シミュレーション計算に用いるバッファについては、DirectX 11で標準仕様となったランダムアクセス可能なAppend Structured Buffer(ASB)を使用している。パーティクルの増減管理にはこのASBを用いて行っており、実際の実装では、2つのASBを用いている。これはA,B二枚のASBにおいて、ASB Aを処理した結果をASB Bに書き込み、次の時間帯ではASB Bを処理した結果をASB Aに書き込む……というようなピンポン式処理を行うためだ。

実際のおおまかなシミュレーションの処理は、各パーティクルの時間を進め、移動量を計算し、衝突判定を行い、消滅判定を行い、処理結果を反対側のASBへと書き出していうような処理系になる。

DirectComputeの起動に際しては、GPU側でのDirectCompute実行処理が終わるたびに、CPU側が有効パーティクル数を問い合わせて、再び有効パーティクル数分、DirectComputeを起動する……というようなCPU-GPUリードバックを回避するために、GPUが独立してCPUに対して非同期にDirectComputeを起動できるIndirectDispatch命令を活用している。こうしたGPU自らが、CPUと非同期にオペレーション発動を行う術はDirectX 10あたりから続々と導入されつつある。

DirectComputeによる実装。各パーティクルは図中のような構造体で表現される

各パーティクルのシミュレーションの流れ

CPU非同期のDirectCompute起動

DirectComputeによってASBに格納されたシミュレーション結果を、グラフィックス描画をするためにバッファの変換をする必要がある。Windows版ロストプラネット2では、これにはByteAddressBuffer(BAB)を利用している。具体的には、頂点バッファ(Vertex Buffer)を、BABとして定義し、DirectCompute側からは、ASBの内容をBAB定義された頂点バッファへコピーしている。

グラフィックスのレンダリングのためにパーティクルバッファから頂点バッファへ

DirectComputeでパーティクルデータだった情報は、このコンバージョン処理で3Dグラフィックスレンダリング用の頂点バッファへ変貌するわけだ。

この頂点情報化されたパーティクルを、凹凸を表す明暗(濃淡)グラフィックスとしてテクスチャにレンダリングする。この描画においてもDrawInsancedIndirectを利用することでCPU処理をバイパスしたレンダリングが行われている。

さて、このままだと凹凸が離散的でイボのようなポツポツ感が露呈してしまうので、フィルター処理でぼかしてポツポツ感を低減する。この凹凸を濃淡テクスチャはハイト(高さ)マップと見なして、今度はこれを法線ベクトルと高さ情報からなるディスプレースメントマップへと変換する。

最終的には、このディスプレースメントマップを元に、水面をレンダリングする。実際には、冒頭で述べたような、何もしないでも出続けている平和な状態の水面の波と合成されてレンダリングされることになる。

パーティクルのレンダリング結果からディスプレースメントマップへの変換

動画
平和な状態の波はキャンセルされたWave Particles法による波だけの映像
(WMV形式 10秒 5.33MB)
動画
DirectComputeが動作して更新しているパーティクルバッファの内容を可視化した映像
(WMV形式 10秒 6.4MB)