2010-12-04 28 views
6

Estoy tratando de escribir un sombreado de desenfoque para el iPad. Lo tengo funcionando, pero no estoy muy contento con los resultados. Obtengo velocidades de cuadros muy entrecortadas y el desenfoque parece basura cuando la cantidad de desenfoque es alta.El sombreador de fragmentos OpenGL ES 2.0 para desenfocar es lento y de baja calidad

¿Alguna idea sobre cómo mejorar las cosas?

un ejemplo de salida:

alt text

uniform sampler2D texture; 
varying mediump vec2 fragTexCoord; 
varying mediump vec3 eyespaceNormal; 

varying highp float blurAmount; 

void main(void) 
{ 
    highp vec2 gaussFilter[7]; 
    gaussFilter[0] = vec2(-3.0, 0.015625); 
    gaussFilter[1] = vec2(-2.0, 0.09375); 
    gaussFilter[2] = vec2(-1.0, 0.234375); 
    gaussFilter[3] = vec2(0.0, 0.3125); 
    gaussFilter[4] = vec2(1.0, 0.234375); 
    gaussFilter[5] = vec2(2.0, 0.09375); 
    gaussFilter[6] = vec2(3.0, 0.015625); 

    highp float blurSize = blurAmount * 1.0; 

    ///////////////////////////////////////////////// 
    // 7x1 gaussian blur fragment shader 
    ///////////////////////////////////////////////// 

    highp vec4 color = vec4(0,0,0,1); 

    for(int i = 0; i < 7; i++) 
    { 
     color += texture2D(texture, vec2(fragTexCoord.x+gaussFilter[i].x*blurSize, fragTexCoord.y+gaussFilter[i].x*blurSize))*gaussFilter[i].y; 
    } 

    gl_FragColor = color; 
} 

Editar: Un borrón cuadro puede ser el camino a seguir. Aquí está una versión de caja desenfoque del shader:

highp vec4 color = vec4(0,0,0,1); 

color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 4.0*blurAmount)) * 0.05; 
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 3.0*blurAmount)) * 0.09; 
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 2.0*blurAmount)) * 0.12; 
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - blurAmount)) * 0.15; 
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y)) * 0.16; 
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + blurAmount)) * 0.15; 
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 2.0*blurAmount)) * 0.12; 
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 3.0*blurAmount)) * 0.09; 
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 4.0*blurAmount)) * 0.05; 

gl_FragColor = color; 

Aquí está la salida de la caja de desenfoque (tenga en cuenta que es sólo un desenfoque horizontal, pero podría ser suficiente para lo que quiero): alt text

Respuesta

10

dicho sombreado tiene que ejecutar dos veces para que funcione, lo que se llama blurSize debe haber una vec2 y el valor de que debe haber vec2(0, 1.0/height) de desenfoque vertical y vec2(1.0/width, 0) de desenfoque horizontal.

Ver http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=240334

La idea detrás de hacer un borrón de dos pasadas es que reducirá drásticamente el número de búsquedas de textura y es de esperar aumentar la velocidad. Un desenfoque de dos pasos con un tamaño de kernel de 7x7 requerirá 14 búsquedas de textura, pero si se hace en un bucle anidado necesitarás hacer 49 búsquedas de textura.

+0

Sí, creo que fue mi error al adaptar el código. Gracias. Creo que realmente no necesito un Gaussian completo para mis propósitos, por lo que la simple imagen borrosa funcionaría lo suficientemente bien y sería más rápido. – Brian

1

¡Es no está claro qué está haciendo exactamente tu código. Está utilizando texture2D que sugiere un filtro 2D. Sin embargo, su matriz de convolución tiene una dimensión y solo realiza un ciclo una vez. Puedo estar equivocado, pero parece que estás aplicando el desenfoque diagonalmente. Si está destinado a ser un filtro 2D, necesitaría dos bucles (anidados) para xey respectivamente para cubrir un área 2D.

Y sobre la variable blurSize - su nombre es un poco engañoso. El tamaño del desenfoque depende de su matriz de convolución. Tu es de 7 píxeles de ancho. Eso determina el tamaño. La variable es más como una "fuerza" de desenfoque que solo puede atenuar el efecto de la matriz de convolución. Si se les da un valor demasiado alto, surgirán artefactos.

No soy un experto y no he escrito ningún sombreador de píxeles además de "hello world" mandelbrot one. Si no estoy equivocado, el difuminado es uno de los peores para acelerar. La mayoría de las fallas en tiempo real que vi fueron box-blurs. Intente portar algún código desde aquí: gameDev thread.

+0

Decidí probar una caja borrosa. Parece que funciona bastante bien pero aún no lo he probado en mi iPad para ver si es lo suficientemente rápido, pero se ve bastante bien. Voy a publicar el código en mi respuesta anterior. Gracias – Brian

3

Hacer dos o más pases de desenfoque de caja mejora la calidad a un desenfoque casi gaussiano manteniendo el rendimiento relativamente alto. Y los desenfoques de cajas también se pueden acelerar con relativa facilidad. Echar un vistazo a http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf

En cualquier caso, en las escenas más conmovedoras que puede salirse con la representación de menor fidelidad de lo que podría parecer obvio a partir de capturas de pantalla.

Cuestiones relacionadas