shader blur2: Unterschied zwischen den Versionen
(Verhalten an Rändern eingefügt, Array konstant gemacht.) |
(Überarbeitung, besserer Shader, siehe Diskussion) |
||
Zeile 7: | Zeile 7: | ||
|- | |- | ||
|Post-Processing-Shader zum verwischen der Szene. | |Post-Processing-Shader zum verwischen der Szene. | ||
− | |Skeptiker | + | |Skeptiker/Coolcat |
− | |1. | + | |1.1 |
|} | |} | ||
Zeile 19: | Zeile 19: | ||
==Beschreibung== | ==Beschreibung== | ||
− | Dieser Shader verwischt die Szene | + | [[Bild:Gaussian-function-plot.gif|framed|Gauss-Funktion mit [[Bild:sigma.gif]] = 3.2]] |
+ | Dieser Shader verwischt die Szene mit Hilfe einer eindimensionalen Gauss-Funktion: | ||
− | + | [[Bild:Gaussian-function.gif]] | |
− | |||
− | |||
− | |||
− | + | Dabei ist x die Entfernung vom Mittelpunkt und [[Bild:sigma.gif]] die gewünschte [http://de.wikipedia.org/wiki/Varianz Varianz]. Da die Gauss-Funktion relativ aufwendig ist, wurde sie bereits im Bereich x = -5...5 für [[Bild:sigma.gif]] = 3.2 ausgewertet. Die Funktionswerte wurden normalisiert um die Summe auf 1 zu bringen und dann als konstantes Array fest in den Shader eingebaut. | |
− | Da der Shader für jedes Texel der Textur die unmittelbaren | + | 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 zweidimsensionale Gauss-Funktion zu verwenden. |
+ | |||
+ | Über die uniform-Variable <tt>uShift</tt> kann gesteuert werden wie der Effekt angewendet wird: | ||
+ | * <tt>uShift = vec2(1.0/textureWidth, 0.0)</tt> bewirkt einen horizontalen Filter | ||
+ | * <tt>uShift = vec2(0.0, 1.0/textureHeight)</tt> bewirkt einen vertikalen Filter | ||
+ | * <tt>uShift = vec2(1.0/textureWidth, 1.0/textureHeight)</tt> bewirkt einen diagonalen Filter | ||
+ | |||
+ | Um den Effekt zu verstärken gibt es verschiedene Möglichkeiten. Beispielsweise kann man etwas wie <tt>uShift = vec2(1.4/textureWidth, 0.0)</tt> 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 [[Bild:sigma.gif]] 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 [[Bild:sigma.gif]] 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== | ==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. | + | 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== | ==Code== | ||
Zeile 40: | Zeile 46: | ||
void main() { | void main() { | ||
− | |||
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; | gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; | ||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; | gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; | ||
Zeile 50: | Zeile 55: | ||
#version 120 | #version 120 | ||
− | uniform sampler2D | + | uniform sampler2D uTexture; |
− | uniform | + | uniform vec2 uShift; |
− | + | ||
− | + | const int gaussRadius = 11; | |
− | + | const float gaussFilter[gaussRadius] = float[gaussRadius]( | |
− | const float gaussFilter[ | + | 0.0402,0.0623,0.0877,0.1120,0.1297,0.1362,0.1297,0.1120,0.0877,0.0623,0.0402 |
− | 0. | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
); | ); | ||
− | + | ||
void main() { | void main() { | ||
− | + | vec2 texCoord = gl_TexCoord[0] - float(int(gaussRadius/2)) * uShift; | |
− | + | vec3 color = vec3(0.0, 0.0, 0.0); | |
− | + | for (int i=0; i<gaussRadius; ++i) { | |
− | for (int i = 0; i < | + | color += gaussFilter[i] * texture2D(uTexture, texCoord).xyz; |
− | + | texCoord += uShift; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | gl_FragColor = vec4(color,1.0); | |
− | gl_FragColor = color; | ||
} | } | ||
</source> | </source> |
Version vom 24. Dezember 2009, 15:55 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 zweidimsensionale 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] - 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);
}