2011-11-07 18 views
5

Image of shader resultGLSL Gif Dither Efecto: Optimización

Tengo un shader de fragmento que dice esencialmente el alfa del color y la traduce en un efecto de difuminado a través de los píxeles.

Sin embargo, es bastante intensivo en el procesador con todas las instrucciones mods y if. ¿Alguien tiene alguna recomendación para optimizar el código a continuación?

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; 
     } 
    } 
} 

Aquí está la solución basada en la retroalimentación:

 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

tiene nombres muy genéricos para sus variables. Sería mucho más fácil averiguar cuál es tu algoritmo si usaras nombres más expresivos. –

Respuesta

6

Lo que intenta hacer es seleccionar si cada píxel debe encenderse en una cuadrícula de 4x4 basada en la fuente alfa. Lo más simple es hacer eso.

Primera inicializar una textura 4x4 con las alfas correspondientes que están obligados a tener el pase pixel (I recogieron 1,0 como el alfa por nunca muestra aquí)

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 

instalación de esta textura con repetición para evitar la mod completamente y un filtro más cercano para evitar el filtrado lineal.

A continuación, utilice una muestra de esa textura para decidir si se enciende el píxel.

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

Esto supone que r nunca es 1. Hay formas simples de evitar esto, p. Ej. divida los valores en la textura 4x4 por 2, excepto los 1.0, y luego multiplique la oscilación por 2 antes de la prueba if, pero después de la recuperación.

Algunas optimizaciones potenciales adicionales:

  • puede evitar el caso de la prueba por completo mediante el uso de una textura con la comparación (textura de sombra).
  • puede evitar el/4 mediante el uso de las instrucciones textureFetch
+0

¡gracias! mis shaders finales se ven así: – miketucker

-1

En primer lugar, su color fragmento será el mismo, independientemente de los resultados de las sentencias if ya que el color se fija en el comenzando.

En segundo lugar, el uso de declaraciones if con nada más hace que su código se ejecute a través de cada cálculo sin importar nada.

Una mejor manera de hacer esto sería tener:

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; 
} 

Por supuesto, esto no le ayudará a cambiar la salida ya que el color no es nunca cambia (como he mencionado anteriormente). Pero esto debería hacer que las cosas se ejecuten un poco más rápido.

Otra cosa a tener en cuenta es qué casos se ejecutan con más frecuencia. Supuse que los casos con r grande son más comunes, de ahí el orden de los enunciados if. Si las pequeñas r's son más comunes, entonces invertir el orden y tener r < 0.1, r < 0.3, r < 0.5, r < 0.7, r < 0.9 tendría más sentido.

El objetivo aquí es hacer que el código salga lo más rápido posible (es decir, que uno de los if sea verdadero). Una vez que uno de los if devuelve true, el resto se ignora, lo que evita que se calcule el resto de las operaciones de mod.

+3

"Antes que nada, el color de tu fragmento será el mismo, independientemente de los resultados de las declaraciones if, ya que el color se establece al principio". Eso no es cierto. Puede establecer salidas de etapa de sombreado varias veces; solo el último es tomado. Incluso puede hacer modificaciones in situ a ellos. –

+0

Lo siento si no estaba claro. Lo que quiero decir es que dado que el color se asigna fuera de los bucles if, el resultado de cada bucle individual será el mismo independientemente de cuál sea verdadero (r> 0,9 da el mismo color de fragmentación que r> 0.1). (A menos que haya algo completamente erróneo en mi comprensión de cómo funcionan los sombreadores). – NickLH

+0

Pero solo configuran ese color si tienen esa condición 'mod 'adicional. De lo contrario, solo usan el color predeterminado de 0. No es solo 'r> X'. –