DGL
https://delphigl.com/forum/

Gauss-Shader
https://delphigl.com/forum/viewtopic.php?f=20&t=7433
Seite 1 von 1

Autor:  Seth [ Di Apr 15, 2008 15:29 ]
Betreff des Beitrags:  Gauss-Shader

hi,

dieses Mal kein Problem, sondern einfach nur einen Shadercode den ich posten möchte.
Vielleicht kann ihn sich jemand noch einmal durchsehen, dann könnte er nämlich ins wiki.
Es handelt sich um einen Gauß-Shader. Die Standardabweichung lässt sich mittels uniform übergeben und die Größe der Filtermatrix lässt sich im Shader einstellen. (Vielleicht gibt es ja auch hier eine Möglichkeit diese zu übergeben)
Des weiteren muss noch die Texturgröße via width und height übergeben werden.

Vertex-Shader:
Code:
  1. varying vec2 texCoord;
  2.  
  3. void main(void)
  4. {
  5.   // Transformation (Modelview und Projection)
  6.   gl_Position = ftransform();
  7.   // Texturkoordinaten
  8.   gl_TexCoord[0] = gl_MultiTexCoord0;;
  9. }

Fragment-Shader:
Code:
  1. uniform sampler2D colorMap; // Textur
  2. uniform float width;
  3. uniform float height;
  4. uniform float standardderivation;
  5.  
  6. const int kernelsize = 5;
  7. // Um an die benachbarten Pixel zu kommen
  8. const float step_w = 1.0/width;
  9. const float step_h = 1.0/height;
  10.  
  11. // Konstanten
  12. const float e  = 2.71828;
  13. const float pi = 3.14159;
  14.  
  15. // Gauß Matrix berechnen
  16. void CalculateGaussMatrix(out int Matrix[kernelsize*kernelsize])
  17. {
  18.   int c=0;
  19.   float pconst = 1.0/(sqrt(2.0*pi)*standardderivation);
  20.   float variance = standardderivation*standardderivation;
  21.   for (float i=0.0; i<float(kernelsize); i=i+1.0)
  22.   {
  23.     for (float j=0.0; j<float(kernelsize); j=j+1.0)
  24.     {
  25.       Matrix[c] = int(ceil(pconst * pow(e, -((i*i) + (j*j)) / (2.0 * variance)) * 100.0));
  26.       c++;
  27.     }
  28.   }
  29. }
  30.  
  31. // Filter anwenden
  32. void main(void)
  33. {  
  34.   int c=0;
  35.   int sum=0;
  36.   int M[kernelsize*kernelsize];
  37.   vec2 offset;
  38.   vec4 ColorResult = vec4(0.0, 0.0, 0.0, 0.0);
  39.   CalculateGaussMatrix(M);
  40.   for (float i=0.0; i<float(kernelsize); i=i+1.0)
  41.   {
  42.     for (float j=0.0; j<float(kernelsize); j=j+1.0)
  43.     {
  44.       sum += M[c];
  45.       offset = vec2((-i + float(kernelsize)/2.0) * step_w, (-j + float(kernelsize)/2.0) * step_h);
  46.       ColorResult += texture2D(colorMap, vec2(gl_TexCoord[0]) + offset) * float(M[c]);
  47.       c++;
  48.     }
  49.   }  
  50.   ColorResult /= float(sum);
  51.   gl_FragColor = ColorResult;
  52. }

Sicherlich lässt sich da noch einiges optimieren, zumal die Gauß-Matrix hier ständig neu berechnet werden muss, vielleicht ließe sich dies auch irgendwie auf das Programm auslagern.

mfg

Autor:  Lord Horazont [ Di Apr 15, 2008 15:51 ]
Betreff des Beitrags: 

Hast du das ding mal ausprobiert, so wegen performance und so?
So wie das aussieht, wird das seeehr langsam sein, weil er jeden Frame die Matrix neu berechnet, noch dazu haben wir hier kernelsize² Texturzugriffe, was auch nicht gerade harmlos ist...

Gruß Lord Horazont

Autor:  Seth [ Di Apr 15, 2008 16:56 ]
Betreff des Beitrags: 

Ja, sonderlich schnell ist es wirklich nicht und wirklich großflächige Blurs sind damit nicht möglich.
Ich habe irgendwo gelesen, dass man das Ganze allerdings stark optimieren kann, indem man erst Horizontal und dann Vertikal (oder umgekehrt) blurrt.
Wie stelle ich das an ?

(die Gauß Matrix werde ich dann wohl entweder statisch machen oder mir etwas anderes überlegen ^^)

mfg

Autor:  Lord Horazont [ Di Apr 15, 2008 18:06 ]
Betreff des Beitrags: 

Nun, um erst horizontal und dann vertikal zu blurren, brauchst du entweder zwei Shader oder einen Shader mit einer If (nicht sehr gut auf älteren Karten), auf jeden Fall aber brauchst du zwei Renderpasses. So in der art:
Code:
  1.  
  2. 1. Szene rendern
  3. 2. Framebuffer in eine Textur schreiben
  4. 3. Framebuffer leeren
  5. 4. Die Textur auf den ganzen Bildschirm mit dem 1. Shader rendern
  6. 5. Die Textur mit dem aktuellen Framebufferinhalt überschreiben
  7. 6. Die Textur erneut auf den ganzen Bildschirm rendern, diesmal mit dem 2. Shader


Welcher der beiden Shader jetzt horizontal und welcher vertikal blurrt, ist deine Entscheidung. Der Blur läuft ansonsten ganz normal ab, nur dass du anstatt kernelsize² "nur" kernelsize Texturzugriffe hast und der Shader auch auf älteren karten, wo die Schleife entrollt werden müsste, noch eine Chance hat durch den Maximal Instruction-Filter durchzukommen :wink:. Du musst halt anstatt einen Kreisförmigen Blur anzustellen nur nach oben und unten oder zur Seite gehen.

Gruß Lord Horazont

Autor:  Seth [ Mi Apr 16, 2008 12:26 ]
Betreff des Beitrags: 

hi, das scheint in der Praxis ganz gut zu funktionieren. Ich nutze allerdings momentan eine Textur in die ich rendere. Lande aber gerade einmal bei 30fps, fast unabhängig von der Texturgröße, hat also vielleicht nichts mit dem Shader zu tun.

mfg

Autor:  Lord Horazont [ Mi Apr 16, 2008 17:49 ]
Betreff des Beitrags: 

Es könnte daran liegen, dass dein Shader in Softwaremodus gehauen wird, wegen den vielen Texturzugriffen und instruktionen.

Und wenn du eine Textur nutzt, in die du renderst sehe ich gerade kein Problem, eine Horizontal/Vertikal Lösung zu verwenden oder reden wir da gerade aneinander vorbei?

Gruß Lord Horazont

Autor:  Seth [ Mi Apr 16, 2008 18:39 ]
Betreff des Beitrags: 

nein, genauso mache ich es ja momentan ;)
die shader sind nicht sehr lang, wie kann ich überprüfen ob der im SW modus läuft ?

Das hier ist der horizontale, der vertikale sieht genauso aus:
Code:
  1. uniform sampler2D colorMap; // Textur
  2. uniform float width;
  3. uniform float height;
  4.  
  5. // Um an die benachbarten Pixel zu kommen
  6. const float step_w = 1.0/width;
  7. const float step_h = 1.0/height;
  8.  
  9. // Konstanten
  10. const float e  = 2.71828;
  11. const float pi = 3.14159;
  12.  
  13. // Filter anwenden
  14. void main(void)
  15. {  
  16.   int c=0;
  17.   int sum=0;
  18.   int M[49];
  19.   M[0]=0;M[1]=1;M[2]=1;[3]=1;M[4]=1;M[5]=1;M[6]=1;M[7]=1;M[8]=1;
  20.   M[9]=2;M[10]=2;M[11]=2;M[12]=2;M[13]=2;M[14]=2;M[15]=3;M[16]=3;
  21.   M[17]=3;M[18]=3;M[19]=3;M[20]=3;M[21]=3;M[22]=3;M[23]=3;M[24]=3;
  22.   M[25]=3;M[26]=3;M[27]=3;M[28]=3;M[29]=3;M[30]=3;M[31]=3;M[32]=3;
  23.   M[33]=3;M[34]=2;M[35]=2;M[36]=2;M[37]=2;M[38]=2;M[39]=2;M[40]=1;
  24.   M[41]=1;M[42]=1;M[43]=1;M[44]=1;M[45]=1;M[46]=1;M[47]=1;M[48]=0;
  25.  
  26.   vec2 offset;
  27.   vec4 ColorResult = vec4(0.0, 0.0, 0.0, 0.0);
  28.   for (float i=0.0; i<49.0; i=i+1.0)
  29.   {
  30.     sum += M[c];
  31.     offset = vec2((-i + 49.0/2.0) * step_w, 0);
  32.     ColorResult += texture2D(colorMap, vec2(gl_TexCoord[0]) + offset) * float(M[c]);
  33.     c++;
  34.   }  
  35.   ColorResult /= float(sum);
  36.   gl_FragColor = ColorResult;
  37. }

height und step_h kann ich in diesen fall ja entfernen ;)

mfg


// Edit Lossy: Matrix umgebrochen. Geht von der Seitenbreite ja nicht mal auf einem 24"er.

Autor:  Pellaeon [ Do Apr 24, 2008 07:12 ]
Betreff des Beitrags: 

Ich glaube garnicht, das wurde doch schon öfters gefragt, oder?
Auf jeden Fall dürfte es in der Performance doch was gebracht haben, dass du nicht in jedem Durchlauf die Gauß-Matrix berechnest. Das war sicher mit der größte Flaschenhals

Seite 1 von 1 Alle Zeiten sind UTC + 1 Stunde
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/