Diskussion:shader blur2: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
Zeile 11: Zeile 11:
  
 
:Du hast mit allem recht ;-). Ich mach mich nachher ran und füge das noch mit in die Beschreibung ein. Und jau, es sollte durchaus i - 3 und nicht i - 4 heißen ;-). --[[Benutzer:Skeptiker|Skeptiker]] 16:40, 23. Dez. 2009 (CET)
 
:Du hast mit allem recht ;-). Ich mach mich nachher ran und füge das noch mit in die Beschreibung ein. Und jau, es sollte durchaus i - 3 und nicht i - 4 heißen ;-). --[[Benutzer:Skeptiker|Skeptiker]] 16:40, 23. Dez. 2009 (CET)
 +
 +
 +
:Ok, meine optimierte Variante die ich für UC übernommen habe sieht nun wie folgt aus. Ich habe die Fallunterscheidung entfernt und durch die Uniform <tt>uShift</tt> ersetzt. Da die GPU Vektoraddition im Schlaf beherrscht sollte das die beste Lösung sein. Insbesondere ist die Texturgröße darin gleich integriert. Für einen horizontalen Filter setzt man also <tt>uShift</tt> auf <tt>vec2(1.0/textureWidth, 0.0)</tt>. Um bei gleicher Geschwindigkeit den Filter zu verstärken kann auch so etwas wie <tt>1.6/textureWidth</tt> versuchen. Auf diese Weise sind natürlich auch diagonale Filter möglich. Außerdem habe ich die Gauss-Funktion (im Array) vergrößert und stärker abgeschnitten. Texel die nur zu einem 64stel in die Berechnung eingehen lohnen den Aufwand nicht wirklich.
 +
<source lang="glsl">uniform sampler2D uScene;
 +
uniform vec2 uShift;
 +
 +
varying vec2 vTexCoord;
 +
 +
const int gaussRadius = 11;
 +
const float gaussFilter[gaussRadius] = float[gaussRadius](
 +
0.0402,0.0623,0.0877,0.1120,0.1297,0.1362,0.1297,0.1120,0.0877,0.0623,0.0402
 +
);
 +
 +
void main() {
 +
vec2 texCoord = vTexCoord - float(int(gaussRadius/2)) * uShift;
 +
vec3 color = vec3(0.0, 0.0, 0.0);
 +
for (int i=0; i<gaussRadius; ++i) {
 +
color += gaussFilter[i] * texture2D(uScene, texCoord).xyz;
 +
texCoord += uShift;
 +
}
 +
gl_FragColor = vec4(color,1.0);
 +
}</source>

Version vom 23. Dezember 2009, 19:18 Uhr

Da an dem anderen Blur Shader scheinbar seit Ewigkeiten nichtsmehr gemacht wird hab ich einfach mal diesen hier erstellt. Fragen, Anregungen, Verbesserungsvorschläge? --Skeptiker 22:25, 22. Dez. 2009 (CET)

Der Shader ist sehr gut, bei meinem Vorschlag in diesem Thread habe ich nämlich nicht berücksichtigt, dass die Convolution-Operation kommutativ und assoziativ ist. Der Gauss-Filter ist deshalb nämlich separierbar. Wenn man Rundungsfehler vernachlässigt spielt es beim Ergebnis keine Rolle, ob man einen 2D-Gauss anwendet oder die Operation zweimal mit einem horizontalen bzw. vertikalen 1D-Gauss durchführt. Die zweite Variante spart aber eine große Menge an Texturzugriffen. In diesem Fall 7*7=49 Zugriffe beim 2D-Gauss gegen 2*7=14 Texturzugriffe beim zweimaligen 1D-Gauss. Das macht um so mehr aus, je größer der Filter ist. Eigentlich sollte ich solche Dinge besser wissen.
Ok, was zu meckern habe ich natürlich auch ;)
  • Du musst die Ränder der Textur in irgendeiner Form korrekt behandeln. Das kann beispielsweise dadurch geschehen das man GL_TEXTURE_WRAP_* auf GL_CLAMP_TO_EDGE oder GL_CLAMP_TO_BORDER setzt. Sollte man vielleicht erwähnen.
  • Das Array gaussFilter sollte const sein, ich bin mir nicht sicher ob der Shader-Compiler so schlau ist selbst zu bemerken, dass er nur einmal Speicher reservieren muss.
  • Ansonsten kann man, wie du schon selbst sagst, an der Fallunterscheidung natürlich noch etwas feilen, aber dann wäre der Shader wahrscheinlich nicht mehr so leicht zu lesen.
--Coolcat 11:06, 23. Dez. 2009 (CET)


Sollte es nicht float(i - 3) sein? Der Index i läuft von 0 bis 6, damit läuft i-4 von -4 bis 2. Oder habe ich gerade nen Knoten drin? --Coolcat 15:56, 23. Dez. 2009 (CET)
Du hast mit allem recht ;-). Ich mach mich nachher ran und füge das noch mit in die Beschreibung ein. Und jau, es sollte durchaus i - 3 und nicht i - 4 heißen ;-). --Skeptiker 16:40, 23. Dez. 2009 (CET)


Ok, meine optimierte Variante die ich für UC übernommen habe sieht nun wie folgt aus. Ich habe die Fallunterscheidung entfernt und durch die Uniform uShift ersetzt. Da die GPU Vektoraddition im Schlaf beherrscht sollte das die beste Lösung sein. Insbesondere ist die Texturgröße darin gleich integriert. Für einen horizontalen Filter setzt man also uShift auf vec2(1.0/textureWidth, 0.0). Um bei gleicher Geschwindigkeit den Filter zu verstärken kann auch so etwas wie 1.6/textureWidth versuchen. Auf diese Weise sind natürlich auch diagonale Filter möglich. Außerdem habe ich die Gauss-Funktion (im Array) vergrößert und stärker abgeschnitten. Texel die nur zu einem 64stel in die Berechnung eingehen lohnen den Aufwand nicht wirklich.
uniform sampler2D uScene;
uniform vec2 uShift;

varying vec2 vTexCoord;

const int gaussRadius = 11;
const float gaussFilter[gaussRadius] = float[gaussRadius](
	0.0402,0.0623,0.0877,0.1120,0.1297,0.1362,0.1297,0.1120,0.0877,0.0623,0.0402
);
 
void main() {
	vec2 texCoord = vTexCoord - float(int(gaussRadius/2)) * uShift;
	vec3 color = vec3(0.0, 0.0, 0.0); 
	for (int i=0; i<gaussRadius; ++i) { 
		color += gaussFilter[i] * texture2D(uScene, texCoord).xyz;
		texCoord += uShift;
	}
	gl_FragColor = vec4(color,1.0);
}