2011-11-07 9 views
5

Image of shader resultGLSLのGIFディザ効果:最適化

私は基本的に色のアルファを読み込み、各画素間でディザリング効果に変換し、フラグメントシェーダを持っています。

しかし、すべてのmodとif文ではかなりプロセッサが集中しています。 以下のコードを最適化するための推奨事項はありますか?

varying vec2 the_uv; 
varying vec4 color; 

void main() 
{ 
    // The pixel color will correspond 
    // to the uv coords of the texture 
    // for the given vertice, retrieved 
    // by the Vertex shader through varying vec2 the_uv 

    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); 
    vec4 tex = texture2D(_MainTex, the_uv); 
    tex = tex * color ; 
    float r = tex.a; 

    if (r > 0.1) { 
     if ((mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 

    if (r > 0.5) { 
     if ((mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 

    if (r > 0.7) { 
     if ((mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 

    if (r > 0.9) { 
     if ((mod(gl_FragCoord.x + 1.0, 4.001) + mod(gl_FragCoord.y + 1.0, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 

    if (r > 0.3) { 
     if ((mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0)) > 6.00) { 
      gl_FragColor = color; 
     } 
    } 
} 

ここでは、フィードバックに基づいてソリューションです:すべての

 varying vec2 the_uv; 
     varying vec4 color; 

     void main() 
     { 
      color = gl_Color; 
      gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
      the_uv = gl_MultiTexCoord0.st; 
     } 
     #endif 

     #ifdef FRAGMENT 
     uniform sampler2D _MainTex; 
     uniform sampler2D _GridTex; 
     varying vec2 the_uv; 
     varying vec4 color; 

     void main() 
     { 
      if (texture2D(_MainTex, the_uv).a * color.a > texture2D(_GridTex, vec2(gl_FragCoord.x, gl_FragCoord.y)*.25).a) gl_FragColor = color; 
      else gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); 

     } 
+0

あなたは、変数のための非常に一般的な名前を持っているを使用して/ 4を回避することができます。より表現力のある名前を使用すると、アルゴリズムがどのようなものかを簡単に把握することができます。 –

答えて

6

あなたがしようとしているのは、ソースアルファに基づいて4x4グリッド上で各ピクセルを点灯するかどうかを選択することです。それを行うのが一番簡単なのはそれだけです。

まず完全にMODを回避するために、繰り返しとセットアップこのテクスチャ

1.0 0.5 1.0 0.1 
1.0 1.0 0.9 1.0 
1.0 0.3 1.0 0.7 
1.0 1.0 1.0 1.0 

(私はここに示したことがないため、アルファとして1.0を選んだ)ピクセルパスを持っている必要があり、対応するアルファと4x4の質感を初期化します、および線形フィルタリングを避けるために最も近いフィルタを含む。

次に、そのテクスチャのサンプリングを使用して、ピクセルを点灯するかどうかを決定します。

vec4 dither = texture2D(_my4x4, gl_FragCoord/4.); // 4 is the size of the texture 
if (r > dither) { gl_FragColor = color; } 

これは、rが決して1ではないと仮定しています。これを回避する簡単な方法があります。 1.0を除いて4x4テクスチャの値を2で除算し、ifテストの前ではフェッチ後にディザを2倍します。

さらにいくつかの潜在的な最適化:

  • あなたは比較(影テクスチャ)とテクスチャを使用して完全であれば、テストを回避することができます。
  • あなたはtextureFetch命令
+0

ありがとう!私の最終的なシェイダーは次のようになります: – miketucker

-1

まず色がセットされているので、あなたのフラグメントの色は関係なく、if文の結果と同じになります始まり。

第2に、else ifがないif文だけを使用すると、何があっても各計算が実行されます。もちろん

if (r > 0.9) { 
    if ((mod(gl_FragCoord.x + 1.0, 4.001) + mod(gl_FragCoord.y + 1.0, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else if (r > 0.7) { 
    if ((mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else if (r > 0.5) { 
    if ((mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else if (r > 0.3) { 
    if ((mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else if (r > 0.1) { 
    if ((mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0)) > 6.00) { 
     gl_FragColor = color; 
    } 
} 
else{ 
    gl_FragColor = color; 
} 

を、これは(私が以前に述べたように)色が変わることはありませんので、あなたが出力を変更する助けにはなりません。これを行うには

もっと良い方法は、持っていることであろう。しかし、これは物事を少し速く動かすはずです。

他にも、最も頻繁に実行されるケースが考慮されます。私は、大きなrのケースがより一般的であると仮定し、したがってifステートメントの順序付けを行いました。小さいrがより一般的である場合、順序を逆転させ、r < 0.1、r < 0.3、r < 0.5、r < 0.7、r < 0.9を有する方がより合理的である。

ここでのポイントは、コードをできるだけ早く終了させることです(つまり、ifのどれかがtrueを返すようにする)。 ifがtrueを返すと残りは無視され、残りのmod演算はすべて計算されません。

+3

"最初に、色が最初に設定されているため、if文の結果に関係なく、フラグメントの色は同じになります。"それは真実ではない。シェーダステージ出力を複数回設定できます。最後のものだけが取られます。その場での変更を行うこともできます。 –

+0

申し訳ありませんが私は明確でない場合。私は、色がifループの外側に割り当てられているので、個々のifループの結果はどちらが真であろうと関係なく同じである(r> 0.9はr> 0.1と同じ彩色を与える)。 (シェイダーの仕組みを理解していない限り、何かが間違っていない限り)。 – NickLH

+0

しかし、追加の 'mod'条件がある場合にのみ、その色を設定します。それ以外の場合は、単にデフォルトの色0を使用します。単に 'r> X'だけではありません。 –