Chunnomi Online
ストリームアウトを用いた汎用パーティクルシステムの構築
最終更新:
chunnomi
-
view
ここでは、ストリームアウトを用いたパーティクルシステムの構築について説明します。
目的
パーティクルシステムは、類似しながらもランダムな動きを持つ
たくさんの小さな粒子の振る舞いを表現するためのものです。
例えば、炎や雨、煙、爆発、スプリンクラー、魔法のエフェクトといった
様々な現象をシミュレートすることができます。
たくさんの小さな粒子の振る舞いを表現するためのものです。
例えば、炎や雨、煙、爆発、スプリンクラー、魔法のエフェクトといった
様々な現象をシミュレートすることができます。
従来の手法では、CPU上で粒子の位置や速度の更新処理を行い、
その結果(頂点情報)をGPUに毎フレーム送り込んで描画処理を行っていました。
しかし、DirectX10から導入されたストリームアウト機能を使うことで、
粒子の更新(位置や速度)と描画をGPU上だけで完結させることができます。
その結果、CPU上のバッファからGPU上のバッファへ頂点情報をコピーする
処理負荷を削減することができ、さらに、AIや物理といった非描画処理のために
CPUを空けられることにもつながります。
その結果(頂点情報)をGPUに毎フレーム送り込んで描画処理を行っていました。
しかし、DirectX10から導入されたストリームアウト機能を使うことで、
粒子の更新(位置や速度)と描画をGPU上だけで完結させることができます。
その結果、CPU上のバッファからGPU上のバッファへ頂点情報をコピーする
処理負荷を削減することができ、さらに、AIや物理といった非描画処理のために
CPUを空けられることにもつながります。
方法
ここでは具体例として、降雨表現の実装を紹介します。
雨粒はわずかな傾きを持って下降しますが、これを表現するためには、
幅が1ピクセルの線分を描画すれば十分でしょう。したがって、各パーティクルを
ジオメトリシェーダによってポイントからラインへと展開することにします。
これは、木のビルボードの例で、ポイントから矩形に展開していたのとは異なることになります。
また、カメラより上のランダムな位置に雨粒を発生させることにします。
つまり、雨が降っているという演出をするためには、世界全体に雨を降らせる必要は無く、
カメラの近辺にのみパーティクルを生成すれば十分だということです。
雨粒はわずかな傾きを持って下降しますが、これを表現するためには、
幅が1ピクセルの線分を描画すれば十分でしょう。したがって、各パーティクルを
ジオメトリシェーダによってポイントからラインへと展開することにします。
これは、木のビルボードの例で、ポイントから矩形に展開していたのとは異なることになります。
また、カメラより上のランダムな位置に雨粒を発生させることにします。
つまり、雨が降っているという演出をするためには、世界全体に雨を降らせる必要は無く、
カメラの近辺にのみパーティクルを生成すれば十分だということです。
ストリームアウト機能の概要
DirectX10から導入されたストリームアウト機能によって、頂点バッファに
GPUから処理結果を書き込むことができます。具体的には、ジオメトリシェーダから
頂点バッファにジオメトリ(頂点データ)をストリームアウトすることが可能です。
そしてさらに、ストリームアウトされたジオメトリを後に通常通り描画することもできます。
GPUから処理結果を書き込むことができます。具体的には、ジオメトリシェーダから
頂点バッファにジオメトリ(頂点データ)をストリームアウトすることが可能です。
そしてさらに、ストリームアウトされたジオメトリを後に通常通り描画することもできます。
2つのパス
今回実装するパーティクルシステムでは、2つのパスを使います。
- 1 パーティクルシステムを生成/更新/破棄するためのストリームアウト専用パス
- 2 パーティクルシステムを描画するための通常パス
これによって、パーティクルシステムの処理を完全にGPU上のみで完結させることができます。
こうするための主な理由としては、処理効率が挙げられます。CPUからGPUに対してデータを送りこむことは、
少なくない負荷がかかるからです。 さらに、CPUからGPUへと処理を移すことによって、
AIや挙動といった処理のためにCPUを空けることができます。
こうするための主な理由としては、処理効率が挙げられます。CPUからGPUに対してデータを送りこむことは、
少なくない負荷がかかるからです。 さらに、CPUからGPUへと処理を移すことによって、
AIや挙動といった処理のためにCPUを空けることができます。
ストリームアウト専用パス
通常描画パス
ストリームアウトのための頂点バッファ生成
頂点バッファをSOステージにバインドしてGPUが書き込みを行えるように、D3D11_IND_STREAM_OUTPUフラグを指定して
頂点バッファを生成する必要があります。一般的にストリームアウトの対象として使われる頂点バッファは、
後に描画パイプラインへの入力としても使われます(つまり、描画するためにIAステージにもバインドされます).
したがって、D3D11_BIND_VERTEX_BUFFERバインドフラグも指定する必要があります。
頂点バッファを生成する必要があります。一般的にストリームアウトの対象として使われる頂点バッファは、
後に描画パイプラインへの入力としても使われます(つまり、描画するためにIAステージにもバインドされます).
したがって、D3D11_BIND_VERTEX_BUFFERバインドフラグも指定する必要があります。
SOステージへのバインドとアンバインド
D3D11_BIND_STREAM_OUTPUTバインドフラグを指定して作成した頂点バッファは、次の関数を使って
SOステージへとバインドすることができます。
SOステージへとバインドすることができます。
<コード>
頂点バッファはSOステージとIAステージに同時にバインドすることはできません。
頂点バッファをSOステージからアンバインド(バインドの解除)するには、
別のバッファ(ヌルでも構いません)を SOステージへとバインドし直します。
頂点バッファをSOステージからアンバインド(バインドの解除)するには、
別のバッファ(ヌルでも構いません)を SOステージへとバインドし直します。
ピンポン方式による頂点バッファの切り替え
1つの頂点バッファをSOステージとIAステージに同時にバインドすることはできません。
そこで、ピンポン方式による頂点バッファの切り替えを行います。
ストリームアウトを使った処理を行う場合には少なくとも、2つのバッファを使いますが、
片方が入力バッファ、もう片方が出力バッファになります。次のフレームでは、2つのバッファの役割が
入れ替わります。つまり、前回ストリームアウトされたバッファが今回の入力バッファになり、
前回の入力バッファが今回ストリームアウトされる対象になります。
そこで、ピンポン方式による頂点バッファの切り替えを行います。
ストリームアウトを使った処理を行う場合には少なくとも、2つのバッファを使いますが、
片方が入力バッファ、もう片方が出力バッファになります。次のフレームでは、2つのバッファの役割が
入れ替わります。つまり、前回ストリームアウトされたバッファが今回の入力バッファになり、
前回の入力バッファが今回ストリームアウトされる対象になります。