2

「Bulding an Advanced Particle System」(John van der Burg 著、Game Developer Magazine、2000 年 3 月) で概説されているアイデアと概念に基づいて、2D パーティクル システムを実装しました。

今、私はこのシステムにどのようなパフォーマンスを期待すべきか疑問に思っています. 私は現在、すべてのパーティクルがフレームごとに更新される単純な (未完成の) SDL/OpenGL プラットフォーマーのコンテキスト内でテストしています。描画は次のように行われます

// Bind Texture
glBindTexture(GL_TEXTURE_2D, *texture);
// for all particles
    glBegin(GL_QUADS);
    glTexCoord2d(0,0);  glVertex2f(x,y);
    glTexCoord2d(1,0);  glVertex2f(x+w,y);
    glTexCoord2d(1,1);  glVertex2f(x+w,y+h);
    glTexCoord2d(0,1);  glVertex2f(x,y+h);
    glEnd();   

1 つのテクスチャがすべてのパーティクルに使用されます。

3000粒程度まではスムーズに動きます。正直なところ、特にこれは画面上の複数のシステムで使用することを意図しているため、もっと多くのことを期待していました. スムーズに表示されるパーティクルの数はいくつですか?

PS: 私は C++ と OpenGL も同様に比較的新しいので、どこかでめちゃくちゃになったのかもしれません!?

使用して編集POINT_SPRITE

glEnable(GL_POINT_SPRITE);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); 

// for all particles
    glBegin(GL_POINTS);
    glPointSize(size);
    glVertex2f(x,y);
    glEnd();

glDisable( GL_POINT_SPRITE );

使うのと性能差が全然わからないGL_QUADS!?

使用して編集VERTEX_ARRAY

// Setup
glEnable (GL_POINT_SPRITE);                                         
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);              
glPointSize(20);                                    

// A big array to hold all the points
const int NumPoints = 2000;
Vector2 ArrayOfPoints[NumPoints];
for (int i = 0; i < NumPoints; i++) {
    ArrayOfPoints[i].x = 350 + rand()%201;
    ArrayOfPoints[i].y = 350 + rand()%201;
}

// Rendering
glEnableClientState(GL_VERTEX_ARRAY);     // Enable vertex arrays
glVertexPointer(2, GL_FLOAT, 0, ArrayOfPoints);     // Specify data
glDrawArrays(GL_POINTS, 0, NumPoints);  // ddraw with points, starting from the 0'th point in my array and draw exactly NumPoints

VA を使用すると、上記のパフォーマンスに違いが生じました。その後、VBO を試してみましたが、実際にはパフォーマンスの違いは見られませんか?

4

2 に答える 2

4

このソリューションにどれだけ期待できるかはわかりませんが、改善する方法はいくつかあります。

まず、glBegin() と glEnd() を使用することで、即時モードを使用しています。これは、私の知る限り、物事を行う最も遅い方法です。さらに、現在の OpenGL 標準にも存在しません。

OpenGL 2.1 の場合

ポイントスプライト:

ポイント スプライトを使用することもできます。私はそれらを使用してパーティクルシステムを実装し、素晴らしいパフォーマンスを思いつきました (少なくとも当時の私の知識では)。ポイント スプライトを使用すると、フレームごとの OpenGL 呼び出しが少なくなり、グラフィック カードに送信されるデータが少なくなります (または、グラフィック カードにデータが保存されているかどうかはわかりません)。短いグーグル検索でも、見るべきいくつかの実装が得られるはずです。

頂点配列:

ポイント スプライトを使用しても問題が解決しない場合は、頂点配列をポイント スプライトと組み合わせて使用​​することを検討してください (メモリを少し節約するため)。基本的に、パーティクルの頂点データを配列に格納する必要があります。次に、GL_VERTEX_ARRAY をパラメーターとして glEnableClientState() を呼び出して、頂点配列のサポートを有効にします。その後、glVertexPointer() (パラメーターについては OpenGL のドキュメントで説明されています) を呼び出し、glDrawArrays() を呼び出して粒子を描画します。これにより、OpenGL 呼び出しがフレームあたり 3000 回ではなく、ほんの一握りに減ります。

OpenGL 3.3 以降の場合

インスタンス化:

OpenGL 3.3 以降に対してプログラミングしている場合は、インスタンス化を使用してパーティクルを描画することを検討することもできます。これにより、さらに高速化されるはずです。繰り返しになりますが、Google で簡単に検索すると、それに関するコードを確認できます。

一般に:

SSE の使用:

さらに、頂点の位置を更新する際に時間がかかる場合があります。そのため、速度を上げたい場合は、SSE を使用して更新することを検討できます。正しく実行すると、多くのパフォーマンスが得られます (少なくとも大量のパーティクルで)。

データのレイアウト:

最後に、配列の構造 (SoA) と構造の配列 (AoS) に関するリンク ( divergentcoder.com/programming/aos-soa-explorations-part-1、Benに感謝)を最近見つけました。パーティクル システムの例を使用して、それらがパフォーマンスにどのように影響するかを比較しました。

于 2011-09-22T23:21:58.200 に答える
1

イミディエイトモード(glBegin / End)の代わりに頂点配列を使用することを検討してください:http://www.songho.ca/opengl/gl_vertexarray.html

シェーダーを使用する場合は、「vertexシェーダー」を検索して、プロジェクトにそのアプローチを使用することを検討することもできます。

于 2011-09-22T23:14:25.237 に答える