2011-06-25 3 views
4

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

私はalrdyこのような操作を行うことができます。

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は機能しません。

+1

ソフトウェアレンダラーで実行している場合を除き、私は_strongly_インターレースモードでのレンダリングをお勧めしません。それはもっと悪く見えますが、それ以上のスピードはありません。実際、それは非常に遅くなるかもしれません。インターレースレンダリングは、GPUの自然な2x2ブロックシェーディングを妨害します。 – Damon

+0

私は1080iで動いているテレビに表示されている映像を合成して繋ぎ合わせています。インタレースする必要があります。 – ronag

+3

その場合、Y解像度の1/2ですべてを行い、最後にテクスチャ付きフルスクリーンクワッドを描画し、ステンシルバッファを悪用して奇数ラインをマスクするのはどうですか?このように、少なくとも最後のパスを除き、少なくともGPUに優しいものです。あるいは、ステンシルが利用できない場合、 "明示的なZカリング"を行うこともできます。 – Damon

答えて

5

(要求されたとして、答えるようにコメント)

インターレースの問題点は、(良いソフトウェアの実装をインターレースからは何も得ていないことを意味し、2×2のクラスタ内のシェーダを実行するGPUは、おそらくそれだけで、実際のピクセルを実行する可能性があるということです部分的デリバティブを求める場合を除き、必要です)。

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

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

ステンシルテストは、ピクセルシェーダが実行される前にピクセルを破棄するために使用できます。もちろん、ハードウェアは2x2グループでシェーダを実行しているので、このパスでは何も得られません。しかし、最後のパスであれば問題ありません。これは、取り込まれた1つのテクセルを書き出す単純なシェーダです。より高価なコンポジションシェイダー(重要なもの)は解像度の半分で動作します。
ここにコードを含む詳しい説明があります:fake dynamic branching。このデモでは、ステンシルを使用してライトの範囲外のピクセルを破棄してピクセルを点灯させないようにしています。

ステンシルバッファを必要としない別の方法は、「明示的Zカリング」を使用することです。実際には、これはさらに簡単で高速になる可能性があります。
これを行うには、Zをクリアし、カラー書き込みを無効にして(glColorMask)、頂点に「近い」Z座標を持つフルスクリーンクワッドを描画し、シェーダーにすべての奇数行のフラグメントをキルさせます、または何でも)。 gl_FragCoord.yは、GLSL 1.0を使用しなければならない場合、別のものになるかもしれない小さなテクスチャを使用して、どの行を削除するかを知る非常に簡単な方法です。
頂点に「遠く離れた」Z値を持つ別のフルスクリーンクワッドを描画します(もちろん、深度テストを使用します)。半透明のテクスチャ(GL_NEARESTフィルタリング)を取り出して書き出します。デプスバッファは1行おきに「近い」値を持つので、それらのピクセルは破棄されます。

どのようにglPolygonStippleとこれを比較しますか?ポリゴンスティプルは、ハードウェアによって直接サポートされていないため、余分なロジックを含めるためにシェーダを「秘密に」書き換えるか、ソフトウェアにフォールバックするかのいずれかによって、エミュレートする必要があります。

3

これはおそらくインターレースを行う正しい方法ではありません。この効果を実際に達成する必要がある場合は、このようなフラグメントシェーダでは行いません。代わりに、ここにあなたが何ができるかです:

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

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

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

  4. 上記のfbo(フレームの内容を含む)の再スケーリング版をステンシルバッファにblitします。

あなたはオフスクリーンFBOのステップをスキップし、ステンシルバッファを使用して直接描画し、これはとにかくクリッピングしようとしているこれらのピクセルをテストするいくつかのフィルレートを浪費することになる可能性があり注意。あなたのプログラムがシェーダ重い場合は、私が言及した解決策が最適になるでしょう。そうでない場合は、がわずかにになることがあります。