shader blur2: Unterschied zwischen den Versionen
K (→Beschreibung) |
I0n0s (Diskussion | Beiträge) K |
||
Zeile 6: | Zeile 6: | ||
!width=20%|Version | !width=20%|Version | ||
|- | |- | ||
− | |Post-Processing-Shader zum | + | |Post-Processing-Shader zum Verwischen der Szene. |
|Skeptiker/Coolcat | |Skeptiker/Coolcat | ||
|1.1 | |1.1 |
Version vom 25. Dezember 2009, 22:07 Uhr
Inhaltsverzeichnis
Blur
Zurück zur Shadersammlung
Beschreibung | Autor | Version |
---|---|---|
Post-Processing-Shader zum Verwischen der Szene. | Skeptiker/Coolcat | 1.1 |
Bilder
Beschreibung
Dieser Shader verwischt die Szene mit Hilfe einer eindimensionalen Gauss-Funktion:
Dabei ist x die Entfernung vom Mittelpunkt und die gewünschte Varianz. Da die Gauss-Funktion relativ aufwendig ist, wurde sie bereits im Bereich x = -5...5 für = 3.2 ausgewertet. Die Funktionswerte wurden normalisiert um die Summe auf 1 zu bringen und dann als konstantes Array fest in den Shader eingebaut.
Um einen zweidimensionalen Blur-Effekt zu erreichen muss der Shader zweimal angewendet werden. Beispielsweise einmal horizontal und einmal vertikal. Dies ist zwar komplizierter aber im allgemeinen schneller, als eine zweidimensionale Gauss-Funktion zu verwenden.
Über die uniform-Variable uShift kann gesteuert werden wie der Effekt angewendet wird:
- uShift = vec2(1.0/textureWidth, 0.0) bewirkt einen horizontalen Filter
- uShift = vec2(0.0, 1.0/textureHeight) bewirkt einen vertikalen Filter
- uShift = vec2(1.0/textureWidth, 1.0/textureHeight) bewirkt einen diagonalen Filter
Um den Effekt zu verstärken gibt es verschiedene Möglichkeiten. Beispielsweise kann man etwas wie uShift = vec2(1.4/textureWidth, 0.0) versuchen. Dies vergrößert die Schrittweite und damit den Einzugsbereich des Shaders. Bei einem zu großen Faktor werden dabei jedoch nicht mehr ausreichend viele Texel der Textur betrachtet. In diesem Fall sollte man eine andere Gauss-Funktion mit größerem und einem weiteren Bereich verwenden. Dadurch steigt natürlich die Anzahl der Texturzugriffe pro Pixel, was eine Grafikkarte schnell ans Limit bringen kann. Aus diesem Grund kann es sinnvoll sein den Shader mehrfach anzuwenden, immer abwechselnd horizontal und vertikal. Dies hat den gleichen Effekt wie ein größeres und benötigt insgesamt weniger Texturzugriffe. Man muss einen Mittelweg aus Texturzugriffen und Renderpasses finden.
Da der Shader für jedes Texel der Textur die unmittelbaren Nachbartexel abtastet, muss das Verhalten an den Rändern der Textur definiert werden, hier empfiehlt sich die Einstellung GL_CLAMP_TO_EDGE oder GL_CLAMP_TO_BORDER.
Besondere Vorraussetzungen
Es handelt sich um einen Post-Processing-Shader, die Szene muss daher vorher in eine Textur gerendert werden. Anschließend muss diese Textur gebunden werden und als Fullscreen-Quad mit diesem Shader gerendert werden. Hier bietet sich ein FrameBufferObject an, insbesondere da der Shader ja zweimal (oder noch öfter) ausgeführt werden muss.
Code
Vertex Shader
#version 120
void main() {
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Fragment Shader
#version 120
uniform sampler2D uTexture;
uniform vec2 uShift;
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 = gl_TexCoord[0].xy - 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(uTexture, texCoord).xyz;
texCoord += uShift;
}
gl_FragColor = vec4(color,1.0);
}