2011-11-07 88 views
5

Image of shader resultGLSL的Gif振盪效果:優化

我有一個片段着色器,基本上讀取彩色字母,並將其轉化爲跨越像素的抖動效果。

但是,它對所有mods和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

您的變量具有非常通用的名稱。如果你使用了更多表達性的名字,那麼更容易找出你的算法。 –

回答

6

你試圖做的是選擇是否每個像素應該基於源阿爾法4x4的方格被點亮。最簡單的做法就是做到這一點。

首先初始化一個4x4紋理與需要具有像素通相應的阿爾法(I拾取1.0作爲alpha用於從未示出在這裏)

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 

設置該紋理具有重複以避免模完全,以及一個最近的過濾器來避免線性過濾。

然後,使用該紋理的取樣,以決定是否光的像素。

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,但在fetch之後。

一些進一步的潛在的優化:

  • 可以通過使用紋理與比較(陰影紋理)避免如果測試完全。
  • 您可以通過使用textureFetch指令來避免/ 4
+0

謝謝!我的最終着色器如下所示: – miketucker

-1

首先,你的碎片的顏色會是一樣的,不管結果的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,其餘的將被忽略,從而避免計算所有其餘的mod操作。

+3

「首先,無論if語句的結果如何,您的片段顏色都是相同的,因爲顏色是在開頭設置的。」這不是真的。您可以多次設置着色器階段輸出;只有最後一個被採取。你甚至可以對它們進行就地修改。 –

+0

對不起,如果我不清楚。我的意思是,因爲顏色被分配到if循環之外,每個單獨的if循環的結果將是相同的,而不管哪一個是真的(r> 0.9給出相同的碎片顏色作爲r> 0.1)。 (除非我對着色器的工作原理有完全錯誤)。 – NickLH

+0

但是,如果他們有額外的'mod'條件,他們只會設置這種顏色。否則,他們只使用0的默認顏色。它不僅僅是'r> X'。 –