2010-12-04 4 views
6

Ich versuche, einen Unschärfe-Shader für das iPad zu schreiben. Ich habe es funktioniert, aber ich bin nicht sehr glücklich mit den Ergebnissen. Ich bekomme sehr choppy Bildraten und die Unschärfe sieht wie Mist aus, wenn Unschärfe hoch ist.OpenGL ES 2.0 Fragment Shader zu verwischen ist langsam und von geringer Qualität

Irgendwelche Ideen, wie man Dinge verbessert?

Einige Beispielausgabe:

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

Edit: Eine Schachtel Unschärfe kann der Weg zu gehen. Hier ist ein Feld Unschärfe Version des Shaders:

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; 

Hier wird die Box Unschärfe Ausgang (beachten Sie, es ist nur eine horizontale Unschärfe, aber es könnte für genug sein, was ich will): alt text

Antwort

10

Das Shader zweimal ausgeführt werden muss, damit es funktioniert, was Sie blurSize nennen vec2 sein sollte, und der Wert, dass sollte vec2(0, 1.0/height) für vertikale Unschärfe und vec2(1.0/width, 0) für horizontale Unschärfe sein.

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

Die Idee, eine zwei Pass Unschärfe hinter tut, ist, dass es dramatisch die Anzahl der Textur Lookups reduzieren und hoffentlich die Geschwindigkeit erhöhen. Eine Zwei-Pass-Unschärfe mit einer Kernel-Größe von 7x7 erfordert 14 Textur-Lookups, aber wenn es in einer verschachtelten Loop gemacht wird, müssen Sie 49 Textur-Lookups machen.

+0

Ja, ich denke, das war mein Fehler bei der Anpassung des Codes. Vielen Dank. Ich denke, dass ich für meine Zwecke nicht wirklich einen vollen Gaussian brauche, also könnte die einfache Box-Unschärfe gut genug funktionieren und schneller sein. – Brian

1

Es ist nicht klar, was genau dein Code macht. Sie verwenden texture2D, das einen 2D-Filter vorschlägt. Ihre Faltungsmatrix hat jedoch eine Dimension und Sie durchlaufen nur einmal eine Schleife. Ich könnte mich irren, aber es scheint, dass Sie die Unschärfe diagonal anwenden. Wenn es sich um einen 2D-Filter handelt, benötigen Sie zwei (verschachtelte) Schleifen für x bzw. y, um einen 2D-Bereich abzudecken.

Und über die Variable blurSize - der Name ist ein bisschen irreführend. Die Größe der Unschärfe hängt von Ihrer Faltungsmatrix ab. Dein ist 7 Pixel breit. Das bestimmt die Größe. Die Variable ist eher eine "Stärke" der Unschärfe, die nur den Effekt der Faltungsmatrix verblassen lässt. Bei zu hohem Wert entstehen Artefakte.

Ich bin kein Experte und habe keinen Pixel Shader neben "Hallo Welt" mandelbrot eins geschrieben. Wenn ich nicht falsch liege, dann ist der Unschärfe-Shader einer der schlechtesten, um schneller zu werden. Die meisten Echtzeit-Unschärfen, die ich sah, waren box-blurs. Versuchen Sie, Code von hier zu portieren: gameDev thread.

+0

Ich entschied mich, eine Box Unschärfe auszuprobieren. Scheint ziemlich gut zu funktionieren, aber ich habe es noch nicht auf meinem iPad ausprobiert, um zu sehen, ob es schnell genug ist, aber es sieht ziemlich gut aus. Ich werde den Code in meiner Antwort oben veröffentlichen. Danke – Brian

3

Wenn Sie zwei oder mehr Unschärfendurchläufe durchführen, wird die Qualität der Gaußschen Unschärfe sehr verbessert, während die Leistung relativ hoch bleibt. Und Box-Unschärfen können relativ einfach beschleunigt werden. Werfen Sie einen Blick auf http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf

In jedem Fall, in den meisten bewegten Szenen können Sie mit niedriger Wiedergabetreue kommen, als von Screenshots offensichtlich.