wir sollen in der Uni jetzt u.a. ein Convolution-Filter implementieren. Allerdings komm ich irgendwie mit den Datentypen im Shader noch nicht ganz klar, wes wegen ich mich im Netz mal ein bisschen umgeschaut habe. Dabei bin ich auf folgenden Code gestoßen:
Code:
// maximum size supported by this shader const int MaxKernelSize = 25;
// array of offsets for accessing the base image uniform vec2 Offset[MaxKernelSize];
// size of kernel (width * height) for this execution uniform int KernelSize;
// value for each location in the convolution kernel uniform vec4 KernelValue[MaxKernelSize];
// image to be convolved uniform sampler2D BaseImage;
void main() { int i; vec4 sum = vec4(0.0);
for (i = 0; i < KernelSize; i++) { vec4 tmp = texture2D(BaseImage, gl_TexCoord[0].st + Offset[i]); sum += tmp * KernelValue[i]; } gl_FragColor = sum; }
Was mein Problem an dem Code ist:
Was ist der Unterschied zw. einem vec2 und einem vec4? Denn vec4(0.0) sieht für mich eher nach nur einer Komponente aus und nicht 4. Also woher weiß ich immer, welchen Datentyp ich brauche?
Im Bild bewegt man sich ja per Offset[i] vor. Was passiert wenn man außerhalb des Bildes ist? Also an Koordinate (0, 0), also Index 0 ist, und dann z.B. 1 abzieht? Löst man das manuell per Fehlerbehandlung, oder hat der Shader da eine passende Fehlerbehandlung? Und gibt es vlt schönere Wege sich im Bild fortzubewegen? (Also das man x+3 bzw y+3 machen kann, anstatt den Offset übergeben zu müssen) Bzw. wie lese ich die Bildgröße aus? (Ich habe im C-Code ja nur noch ein Gluint)
Wie lade ich den Filterkernel am besten hoch? Es muss ja über glUniformMatrix4fv gehen. Wie groß muss die Matrix die ich hochlade bei einem 3x3 Filter sein? 9x4 floats (wegen vec4)? Und in welchen davon müssen meine Filterwerte stehen? Reicht es dann in jedem 4. float einen Wert einzuspeichern, oder muss ein Wert in 4 aufeinanderfolgenden floats erscheinen?
Das Tutorial im Wiki gibt dazu leider nicht wirklich eine richtige Auskunft .
besten Dank im Voraus SunBlack
Zuletzt geändert von SunBlack am So Jun 13, 2010 11:48, insgesamt 1-mal geändert.
Registriert: Di Okt 13, 2009 17:25 Beiträge: 365
Programmiersprache: C++
Hallo! Von Convolution-Filter lese ich das erste Mal etwas, bin da also auch kein Pro. Zu deinen Fragen:
Ein vec2 ist ein Vektor mit zwei Komponenten, also x und y, s und t oder auch u und v. Für jede Komponente gibt es quasi einen float. Vec4 hat vier Komponenten (z.B. xyzw). Dass der vec4-Konstruktor mit nur einem Parameter aufgerufen wird, entspricht glaube ich nicht den GLSL-Regeln. Gemeint ist jedenfalls vec4(0.0, 0.0, 0.0, 0.0).
Was bei Texturkoordinaten > 1 oder < 0 passiert, hängt davon ab, ob du glTexParameteri GL_REPEAT oder GL_CLAMP übergeben hast. Bei GL_REPEAT wird dann gekachelt, sonst wird ein Wert > 1 zu 1 und ein Wert < 0 zu 0.
Den letzten Punkt kann ich dir leider nicht beantworten, da ich mich wie gesagt nicht mit Convolution-Filtern auskenne. glUniformMatrix4fv ist zum hochladen der Daten auf die Grafikkarte vermutlich nicht so geeignet, da ich in deinem GLSL-Code keine Matrix (also z.B. mat4) sehe.
Übrigens, hast du auch schon das Tutorial GLSL gelesen?
Gruß mrtrain
ps: Wie hast du eigentlich die Aufzählungspunkte gemacht? Mit [*] will es bei nicht funktionieren. edit: Danke Lord, jetzt geht's.
Zuletzt geändert von mrtrain am Mi Aug 31, 2011 19:17, insgesamt 2-mal geändert.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Hi SunBlack,
Bevor ich deine Fragen beantworte, hier vielleicht ein andere interessanter Hinweis für dich: Für Convolution-Filter *ohne* Shader gibt es auch: glConvolutionFilter2D. Wie man damit umgeht und was das genau ist, wird hier erklärt: Convolution-Filter. Ohne Shader wird wahrscheinlich schneller funktionieren, da du sonst sehr schnell an das Limit der Texturzugriffe kommst. Dann wechselt OpenGL in den Softwaremodus und es wird richtig langsam. Der ConvolutionFilter2D muss aktiviert werden, bevor du dein Bild an OpenGL hochlädst. Wenn du die fertigen Daten dann auslesen und weiterverarbeiten möchtest, könnte sich glGetTexImage2D lohnen. Eventuell wird dieses sogar auch vom ConvolutionFilter beeinflusst. Dann lohnt es sich, erst das Bild *ohne* aktivierten Filter hochzuladen, dann den Filter aktivieren und das Bild wieder von OpenGL mit genanntem Befehl zurückholen. So kannst du unterschiedliche Filter anwenden, ohne das Bild immer wieder zur Grafikkarte übertragen zu müssen. Das ist aber, wie gesagt, nur dann interessant, wenn du die Daten später weiterverarbeiten oder in eine Datei schreiben willst.
SunBlack hat geschrieben:
Was ist der Unterschied zw. einem vec2 und einem vec4? Denn vec4(0.0) sieht für mich eher nach nur einer Komponente aus und nicht 4. Also woher weiß ich immer, welchen Datentyp ich brauche?
Nun, ein vec2 hat zwei Komponenten und ein vec4 eben vier, wie du schon festgestellt hast. vec4(0.0) ist eine verkürzte Schreibweise von vec4(0.0, 0.0, 0.0, 0.0). Für Texturkoordinaten auf zweidimensionalen Bildern nutzt man immer vec2, für Farben und Vertexpositionen vec4.
SunBlack hat geschrieben:
Im Bild bewegt man sich ja per Offset[i] vor. Was passiert wenn man außerhalb des Bildes ist? Also an Koordinate (0, 0), also Index 0 ist, und dann z.B. 1 abzieht? Löst man das manuell per Fehlerbehandlung, oder hat der Shader da eine passende Fehlerbehandlung? Und gibt es vlt schönere Wege sich im Bild fortzubewegen? (Also das man x+3 bzw y+3 machen kann, anstatt den Offset übergeben zu müssen) Bzw. wie lese ich die Bildgröße aus? (Ich habe im C-Code ja nur noch ein Gluint)
Es greifen die normalen Texturbehandlungen von OpenGL soweit ich weiß. Außerhalb des gültigen Texturbereiches wird der äußerste Pixel des Bildes bis in die Unendlichkeit wiederholt (vgl. glTexParameter - Vergleich zwischen verschiedenen Texturwraptypen). Generell greifst du in OpenGL auf Texturen (also "Bilder") immer nur mit Koordinaten zwischen 0 und 1 zu. Ein vec2 (0.5, 0.5) würde also genau die Mitte der Textur treffen, egal, wie groß diese ist. Das ist meistens vorteilhaft (man kann einfach hochauflösende Texturen gegen niedriger auflösende austauschen und umgekehrt), in deinem Fall aber nachteilhaft. Die Größe der Textur kannst du im Shader selbst nicht rausbekommen und um anhand der Pixelkoordinaten auf einzelne Bildpunkte zuzugreifen brauchst du irgendein hohes Shadermodel (4 oder so), wird also nicht von jeder Grafikkarte unterstützt. Wie du die Größe der Textur in C nach dem Hochladen zu OpenGL rausbekommst weiß ich gerade leider nicht. Wenn ich pixelgenaue Zugriffe brauchte, habe ich das immer so gelöst, dass ich die Originalgröße der Textur beim Laden in einer Datenstruktur zusammen mit der TexturID (der GLUInt, den du meinst), gespeichert habe.
SunBlack hat geschrieben:
Wie lade ich den Filterkernel am besten hoch? Es muss ja über glUniformMatrix4fv gehen. Wie groß muss die Matrix die ich hochlade bei einem 3x3 Filter sein? 9x4 floats (wegen vec4)? Und in welchen davon müssen meine Filterwerte stehen? Reicht es dann in jedem 4. float einen Wert einzuspeichern, oder muss ein Wert in 4 aufeinanderfolgenden floats erscheinen?
Nein, es geht nicht über glUniformMatrix4fv. Ich sehe bei dem Shader gerade garkeinen Filterkernel, nur Offsets. Die Pixel werden also ungewichtet aufaddiert, es scheint sich nicht wirklich um einen Convolution-Shader zu handeln.
greetings
ps: mrtrain war bei ein paar sachen schneller . @mrtrain: da muss auch noch ein [ list] drum. also [ list][ *]punkt 1[ *]punkt 2[ /list]
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
[*] Ein vec2 ist ein Vektor mit zwei Komponenten, also x und y, s und t oder auch u und v. Für jede Komponente gibt es quasi einen float. Vec4 hat vier Komponenten (z.B. xyzw). Dass der vec4-Konstruktor mit nur einem Parameter aufgerufen wird, entspricht glaube ich nicht den GLSL-Regeln. Gemeint ist jedenfalls vec4(0.0, 0.0, 0.0, 0.0).
Ok, gut. War mir da nicht ganz sicher ob er das so einfach abkam, vor allem da es mich gewundert hat, warum texture2D einen vec4 zurückgibt. Aber man sollte nicht nur an Koordinaten denken, sondern auch mal an Farbwerte (RGBA) die nicht in einer einzelnen Zahl stehen (wie bei Delphi weiß z.B. 16777215 ist ), sondern als Vector getrennt.
mrtrain hat geschrieben:
Übrigens, hast du auch schon das Tutorial GLSL gelesen?
Japp, mein letzter Satz sollte das Andeuten.
Lord Horazont hat geschrieben:
Bevor ich deine Fragen beantworte, hier vielleicht ein andere interessanter Hinweis für dich: Für Convolution-Filter *ohne* Shader gibt es auch: glConvolutionFilter2D.
Leider bringt es mir in der Übung nichts - da sollen wir leider den Shader dazu verwenden - ist halt eine Shaderübung .
Hab eben nachgeschaut GL_CLAMP_TO_EDGE ist eingestellt, also das passende.
Lord Horazont hat geschrieben:
Wenn ich pixelgenaue Zugriffe brauchte, habe ich das immer so gelöst, dass ich die Originalgröße der Textur beim Laden in einer Datenstruktur zusammen mit der TexturID (der GLUInt, den du meinst), gespeichert habe.
Ok schade. Hatte gehofft das Texturgrößenunabhängig machen zu können.
Lord Horazont hat geschrieben:
Nein, es geht nicht über glUniformMatrix4fv. Ich sehe bei dem Shader gerade garkeinen Filterkernel, nur Offsets. Die Pixel werden also ungewichtet aufaddiert, es scheint sich nicht wirklich um einen Convolution-Shader zu handeln.
Über was dann? Achja, hatte den flaschen Code vorhin vond er Quelle kopiert. Habe es mal korrigiert.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Na das sieht doch besser aus. Dann musst du deine Daten über glUniform4fv übergeben. Und zwar legst du dir dafür ein Array an, indem du die Vektoren mit den Faltungskernwerten speicherst. Auch hier handelt es sich wieder um vec4, sodass du jede Farbkomponente und Alpha mit einem anderen Wert belegen kannst. Dann übergibst du an glUniform4fv einen Pointer auf den ersten Wert des Arrays. Ähnlich machst du's mit Offset. Da brauchst du dann ein Array aus vec2-Vektoren, in das du dann den Versatz reinsetzt. Für einen 3x3-Filter würdest du also z.B. die Vektoren (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1) übergeben, wobei die noch mit einem Faktor multipliziert werden müssen, damit du die Pixel auch triffst. Dieser Faktor ist der Kehrwert der Texturgröße in der jeweiligen Dimension, ist also für X und Y unterschiedlich. Für X ist er 1/Width, für Y 1/Height. Irgendwie müsstest du ja beim Laden an die Höhe und Breite der Textur rankommen, oder?
Ich hoffe, das war verständlich
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Hey danke, jetzt ist alles klar. Mein Problem war wohl, dass ich die Farbe die ganze Zeit gedanklich als eine einzige Zahl interpretiert hatte (statt als Vector) und nach dem Fixen das nicht mehr darüber nachgedacht habe, was es bringt 4D-Vectoren zu übergeben (in der Übung davor haben wir alle Farbkompos gleich behandelt, wes wegen ich hier auch die Trennung vergaß )
Eine Randfrage aber noch: Wann verwendet man denn glUniformMatrix4fv, wenn glUniform4fv reicht? Denn wenn ich mir das hier ansehe, sehe ich da keinen bedeutenden Unterschied.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Der bedeutende Unterschied liegt einfach darin, dass die Uniform-Variable im Shader bei dir als vecX deklariert ist, in verlinkten Beispiel als matX. Bei vecX musst du immer glUniformX[fd][v] verwenden, bei matX entsprechend glUniformMatrixX[fd][v].
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Dez 27, 2005 12:44 Beiträge: 393 Wohnort: Berlin
Programmiersprache: Java, C++, Groovy
Hallo,
glConvolutionFilter2D ist deutlich langsamer als ein Shader, zumal dafür die Erweiterung ARB_Imaging benötigt wird, die nicht immer verfügbar ist und ab OpenGL 3.0 als deprecated gilt.
Viele Grüße dj3hut1
_________________ Wenn Gauß heute lebte, wäre er ein Hacker. Peter Sarnak, Professor an der Princeton University
Mitglieder in diesem Forum: 0 Mitglieder und 9 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.