5

GLSLを使用してインターレースモードで効率的にレンダリングしたいと思います。

私は次のようにこれを行うことができます:

vec4 background = texture2D(plane[5], gl_TexCoord[1].st);
if(is_even_row(gl_TexCoord[1].t))
{
    vec4 foreground = get_my_color();
    gl_FragColor = vec4(fore.rgb * foreground .a + background .rgb * (1.0-foreground .a), background .a + fore.a);
}
else
   gl_FragColor = background;

ただし、GLSLでの分岐の性質を理解している限り、「even_row」は実行時の値と見なされるため、両方の分岐が実際に実行されます。

かなり重い関数「get_color」を不必要に呼び出さないようにするために、ここで使用できるトリックはありますか?is_even_rowの動作は非常に静的です。

または、これを行う他の方法はありますか?

注:GLSLコードにカスタムブレンド関数があるため、glPolygonStippleは機能しません。

4

2 に答える 2

6

(要求に応じて、回答するコメント)

インターレースの問題は、GPUが2x2クラスターでシェーダーを実行することです。つまり、インターレースから何も得られません(偏導関数を要求しない限り、優れたソフトウェア実装では、必要な実際のピクセルのみが実行される可能性があります)。

せいぜい、インターレースは同じ速度で実行されますが、最悪の場合、インターレースの余分な作業のために実行速度が遅くなります。数年前、ShaderX4にインターレースレンダリングを提案する記事がありました。私はその方法を半ダースのグラフィックカード(「2つの大きな」メーカーのそれぞれの3世代のハードウェア)で試しましたが、いずれの場合も動作が遅くなりました(場合によってはわずかに、場合によっては最大50%)。

できることは、すべての高価なレンダリングを垂直解像度の1/2で実行することです。これにより、ピクセルシェーダーの作業(およびテクスチャ帯域幅)が1/2に削減されます。次に、テクスチャ(GL_NEAREST)をアップスケールし、1行おきに破棄できます。

ステンシルテストは、ピクセルシェーダーが実行される前にピクセルを破棄するために使用できます。もちろん、ハードウェアは2x2グループでシェーダーを実行しているため、このパスでは何も得られません。ただし、それが最後のパスであるかどうかは関係ありません。これは、フェッチされた単一のテクセルを書き出す簡単なシェーダーです。よりコストのかかるコンポジションシェーダー(重要なもの!)は、半分の解像度で実行されます。
ここにコードを含む詳細な説明があります:偽の動的分岐。このデモでは、ステンシルを使用してライトの範囲外にあるピクセルを破棄することにより、ピクセルの照明を回避します。

ステンシルバッファを必要としない別の方法は、「明示的なZカリング」を使用することです。実際、これはさらに簡単で高速な場合があります。
このためには、Zをクリアし、カラー書き込みを無効にし(glColorMask)、頂点が「近い」Z座標を持つフルスクリーンのクワッドを描画し、シェーダーにすべての奇数行のフラグメントを強制終了させます(または、必要に応じて非推奨のアルファテストを使用します。 )。gl_FragCoord.yは、どの行を強制終了するかを知る非常に簡単な方法です。折り返す小さなテクスチャを使用することもできます(GLSL 1.0を使用する必要がある場合)。
次に、頂点に「遠い」Z値を含む別のフルスクリーンクワッドを描画します(もちろん、深度テストを使用します)。ハーフレゾテクスチャをフェッチして(GL_NEARESTフィルタリング)、書き出すだけです。デプスバッファの値は1行おきに「近い」ため、

glPolygonStippleこれと比べてどうですか?ポリゴンスティプルは非推奨の機能です。ハードウェアで直接サポートされておらず、シェーダーを「密かに」書き直して追加のロジックを含めるか、ソフトウェアにフォールバックすることで、ドライバーがエミュレートする必要があるためです。

于 2011-06-26T14:06:46.920 に答える
3

これはおそらくインターレースを行うための正しい方法ではありません。この効果を本当に実現する必要がある場合は、このようなフラグメントシェーダーで実行しないでください。代わりに、次のことができます。

  1. フルスクリーンの1ビットステンシルバッファを初期化します。各ビットは、対応する行のパリティを格納します。

  2. 通常のように、垂直解像度の1/2の一時的なFBOにシーンをレンダリングします。

  3. ステンシルテストをオンにし、描画するスキャンラインのセットに応じてステンシル機能を切り替えます。

  4. 前述のfbo(フレームのコンテンツを含む)の再スケーリングされたバージョンをステンシルバッファーにブリットします。

オフスクリーンのFBOステップをスキップして、ステンシルバッファーを使用して直接描画することもできますが、これは、とにかくクリップされるピクセルをテストするためのフィルレートを浪費することになります。プログラムのシェーダーが重い場合は、先ほど説明したソリューションが最適です。そうでない場合は、画面に直接描画した方がわずかに良い結果になる可能性があります。

于 2011-06-26T03:16:33.327 に答える