shader blur2: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
(Überarbeitung, besserer Shader, siehe Diskussion)
K (Code)
Zeile 64: Zeile 64:
 
   
 
   
 
void main() {
 
void main() {
vec2 texCoord = gl_TexCoord[0] - float(int(gaussRadius/2)) * uShift;
+
vec2 texCoord = gl_TexCoord[0].xy - float(int(gaussRadius/2)) * uShift;
 
vec3 color = vec3(0.0, 0.0, 0.0);  
 
vec3 color = vec3(0.0, 0.0, 0.0);  
 
for (int i=0; i<gaussRadius; ++i) {  
 
for (int i=0; i<gaussRadius; ++i) {  

Version vom 24. Dezember 2009, 15:58 Uhr

Blur

Zurück zur Shadersammlung

Beschreibung Autor Version
Post-Processing-Shader zum verwischen der Szene. Skeptiker/Coolcat 1.1

Bilder

Vorher
Nachher

Beschreibung

Gauss-Funktion mit sigma.gif = 3.2

Dieser Shader verwischt die Szene mit Hilfe einer eindimensionalen Gauss-Funktion:

Gaussian-function.gif

Dabei ist x die Entfernung vom Mittelpunkt und sigma.gif die gewünschte Varianz. Da die Gauss-Funktion relativ aufwendig ist, wurde sie bereits im Bereich x = -5...5 für 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.

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

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