3

OpenGL で 2D ゲーム用に多数の 2D 円を描画しようとしています。それらはすべて同じサイズで、同じテクスチャーを持っています。多くのスプライトが重なっています。これを行う最速の方法は何ですか?

私が作っているエフェクトの例 http://img805.imageshack.us/img805/6379/circles.png

(黒いエッジは円の爆発が拡大したためであることに注意してください。このスクリーンショットが撮られた直後に塗りつぶされました。

現時点では、テクスチャ付きの三角形のペアを使用して各円を作成しています。円のように見えるように、テクスチャのエッジの周りに透明度を設定します。これにブレンディングを使用すると、非常に遅くなることが判明しました (また、Z カリングは深度バッファーに正方形としてレンダリングされるため、不可能でした)。代わりに、ブレンドを使用していませんが、フラグメント シェーダーでアルファ 0 のフラグメントを破棄します。これは機能しますが、(フラグメントが破棄されるため) 初期の z が不可能であることを意味します。

速度は大量のオーバードローと GPU のフィルレートによって制限されます。円が描画される順序は重要ではありません (フレーム間でちらつきが発生しない限り)。そのため、画面上の各ピクセルが一度だけ書き込まれるようにしています。

深度バッファを使用してこれを試みました。各フレームの開始時に、1.0f にクリアされます。次に、円が描画されると、深度バッファーのその部分が 0.0f に変更されます。別の円が通常そこに描画される場合、新しい円の z も 0.0f であるため、そうではありません。これは現在深度バッファにある 0.0f より小さくないため、描画されません。これは機能し、描画する必要があるピクセル数を減らす必要があります。でも; 奇妙なことに、それはそれ以上速くはありません。この動作 (ポイントが同じ深さの場合、opengl 深さバッファーが遅い)については既に質問しましたが、同じ z 値を使用すると z カリングが加速されないという提案がありました。

代わりに、すべての円に 0 から上向きの偽の Z 値を個別に与える必要があります。次に、glDrawArrays とデフォルトの GL_LESS を使用してレンダリングすると、z カリングにより速度が正しく向上します (ただし、円を可能にするためにフラグメントが破棄されるため、初期の z は不可能です)。ただし、これは理想的ではありません。2D ゲーム用に z 関連のコードを大量に追加する必要があったためです。ただし、これは私が現在見つけた最速の方法です。

最後に、ステンシル バッファーを使用してみました。

glStencilFunc(GL_EQUAL, 0, 1);
glStencilOp(GL_KEEP, GL_INCR, GL_INCR);

ステンシル バッファはフレームごとに 0 にリセットされます。アイデアは、ピクセルが初めて描画された後です。次に、ステンシル バッファーで非ゼロに変更されます。次に、そのピクセルは再度描画されるべきではないため、オーバードローの量が減少します。ただし、これは、ステンシル バッファーまたは深度バッファーなしですべてを描画するよりも高速ではないことが証明されています。

私が試みていることを書くために人々が見つけた最速の方法は何ですか?

4

1 に答える 1

3

基本的な問題は、塗りつぶしが制限されていることです。これは、GPUが、期待する時間内に描画するように要求するすべてのフラグメントをシェーディングできないことです。デプスバッファリングのトリックが効果的でない理由は、処理の最も時間のかかる部分が、デプスのに発生するフラグメントのシェーディング(独自のフラグメントシェーダーまたは固定機能シェーディングエンジンのいずれか)であるためです。テスト。ステンシルを使用する場合にも同じ問題が発生します。ピクセルのシェーディングは、ステンシルの前に行われます。

役立つことがいくつかありますが、それらはハードウェアによって異なります。

  • デプスバッファリングを使用して、スプライトを前面から背面にレンダリングします。最近のGPUは、シェーディングするためにフラグメントを送信する前に、フラグメントのコレクションが表示されるかどうかを判断しようとすることがよくあります。大まかに言えば、デプスバッファ(またはその表現)は、シェーディングされようとしているフラグメントが表示されるかどうかを確認するためにチェックされ、表示されない場合は、その時点で処理が終了します。これは、フレームバッファに書き込む必要のあるピクセル数を減らすのに役立ちます。
  • 次のように、テクセルのアルファ値をすぐにチェックし、追加の処理の前にフラグメントを破棄するフラグメントシェーダーを使用します。

    varying vec2 texCoord;
    uniform sampler2D tex;
    
    void main()
    {
        vec4 texel = texture( tex, texCoord );
    
        if ( texel.a < 0.01 ) discard;
    
        // rest of your color computations
    }
    

(固定機能フラグメント処理でアルファテストを使用することもできますが、フラグメントシェーディングが完了する前にテストが適用されるかどうかを判断することはできません)。

于 2013-02-19T18:03:18.060 に答える