GLSL - Kommunikation zwischen OpenGL-Kontext und Shader
-
50 Texture-Lookups halte ich (insbesondere im Vertex-Shader) nicht fuer besonders praktikabel.
Da die Ergebnisse auch gespeichert werden sollen, waere der Pixel-Shader eigentlich geeigneter.
Schau Dir dazu mal PBO an:Render to vertex array: The application can use a fragment program to render some image into one of its buffers, then read this image out into a buffer object via glReadPixels. Then, it can use this buffer object as a source of vertex data.
In jedem Fall solltest Du Dir eine cache- und datenmengen-freundliche Moeglichkeit ueberlegen, die zugehoerigen Vertices zu definieren.
-
Hmm, ich will ja Punkte in Weltkoordinaten an die GPU senden und da ich jeweils nur den aktuellen Punkt manipulieren will, spielt der Fragemtnshader (=Pixelshader?) doch keine Rolle, oder?
Aber ich sehe ein, dass die Texturzugriffe wohl ineffizient sind. Du schlägst also vor, die ausgewählten Vertices offscreen zu render und an die GPU zu transferieren, verstehe ich das richtig? (sorry, dass ich nachfrage, aber bei mir hat´s noch nicht "klick" gemacht).
Also:
- VBO erstellen:
- binden
- daten ladenunsigned intm_nVBOVertices; glGenBuffersARB( 1, &m_nVBOVertices ); glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices ); glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices,GL_STATIC_DRAW_ARB);Die Frage ist dann: Wie komme ich im Shader an die Daten?
Grüße,
mtx
-
Hm, kann mir bitte jemand einen Tipp geben?
Also ich vereinfache mal: Ich will eine spezielle Anzahl von x,y,z-Koordinaten aus der OpenGL-Umgebung an die GPU senden, damit ich sie dort verarbeiten (glsl) kann.
-
Das grundlegende Probleme ist, dass das Ergebnis des Vertex-Shaders in den Registern des Rasterizers landet. Du moechtest das Ergebnis aber in einem Vertexbuffer speichern.
"Speichern" tut in gewisser Weise der Pixel-Shader indem er Farben in den Framebuffer schreibt.Angenommen Du moechtest jeweils aus n (statischen) Quellvektoren (jeweils x,y,z) einen (dynamischen) Ergebnisvektor (ebenfalls x,y,z) berechnen:
Speicher Deine Quellvektoren in einer Zeiler einer GL_RGB32F_ARB-Textur der Breite n.
Hol Dir die Vektoren per Texture-Lookup, mach die noetigen Berechnungen (je nach Shader-Limit brauchst Du dafuer evtl mehrere Durchgaenge) und lass den Pixel-Shader das Ergebnis im Framebuffer (ebenfalls float) speichern.
Fuer den zweiten Ergebnisvektor liesst Du dann die Quellvektoren aus der zweiten Zeile der Textur usw.
Die Hoehe der Textur und die Breite des Framebuffers sind also identisch zu waehlen (wegen Textur/Kompatibilitaet am besten 2^m).
Effektiv zeichnest Du dann nur ein Quad das einen Pixel hoch ist.
Dem Quad gibst Du zb eine 1D-Textur-Koordinate (0..1) mit, die automatisch fuer jeden "Ergebnispixel" die richtige Zeile aus der "Quellvektor-Textur" adressiert.
Fuer die naechsten "2^m" Ergebnisse (naechste Zeile im Framebuffer) hast Du dann eine weitere Quellvektor-Textur und zeichnest eine weiteres Quad.
Am Ende hast Du alle Vektoren im Framebuffer und kopierst dessen Inhalt einfach in einen Vertexbuffer.Alternativ kannst Du auch alle Quellvektoren in einer (weiteren) Textur unterbringen und in oben erwaehnter Textur statt des tatsaechlichen Quellvektors nur einen Index (in Form einer Texturkoordinate) ablegen. Das wuerde ein wenig Speicher sparen aber dafuer nicht sonderlich cache-effizient sein.
Wenn die Anzahl der Quellvektoren pro Output variiert musst Du die entweder auch irgendwo speichern oder die Quellvektor-Zeile mit neutralen Elementen auffuellen.
Statt pro Zeile eine 2D-Textur zu haben kannst Du auch fuer den gesamten Input eine 3D-Textur nehmen und ein entsprechend hohes Quad zeichnen (jede Zeile adressiert ein anderes 2D-Slice).
Beachte dass beim Texture-Lookup Filtering schaedlich oder nuetzlich sein kann (bringt Dir lineare Interpolation zwischen zwei Quellvektoren umsonst).
-
Danke dir für deine Unterstützung!

Speicher Deine Quellvektoren in einer Zeiler einer GL_RGB32F_ARB-Textur der Breite n.
Da hab ich ja theoretisch zwei Möglichkeiten:
(1) Jeweils eine Koordinatenkomponente (x, y, z)in einem Kanal (r, g, b)speichern
(2) Textur der Breite 3*n wählen und nur einen Kanal benutzen.Ist eine Methode der anderen vorzuziehen?
Und was wichtiger ist: Wie sieht eine mögliche Implementierung aus? Also wie bekomme ich einen konkreten float-Wert in die Textur?Ich hab jetzt (hoffentlich korrekt) ein FBO erstellt und eine Textur erstellt mit:
glGenTextures(1, &tex); //Textur erstellen... glBindTexture(GL_TEXTURE_2D, tex); // ... binden glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST); //... Filtermodei einstellen glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST); //... Filtermodei einstellen glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize, texSize, 0, GL_RGBA8, GL_UNSIGNED_BYTE, NULL); //Platz im Speicher erstellen; glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0); //Textur hinzufügenGrüße,
mtx
-
Textur der Breite 3*n wählen und nur einen Kanal benutzen.
Das haette den Nachteil, dass Du pro Texture-Fetch auch nur ein Skalar auslesen kannst waehrend Du bei einer RGB(A)-Textur pro Lookup einen "ganzen" Vektor bekommst (dessen restliche Komponenten Du ja vermutlich eh irgendwann brauchst).
Also wie bekomme ich einen konkreten float-Wert in die Textur?
Du setzt fuer die Textur ein entsprechendes Format und schreibst nen Float-Buffer rein.
float data[width*height]; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, width, height, 0, GL_RGBA, GL_FLOAT, data );Genauso sollte dann die Textur die Du als Rendertarget an den FBO bindest in einem Floating-Point-Format sein.
-
prima! Danke!
Jetzt frage ich mich allerdings noch, wie ich an die Daten aus dem Shader zugreifen kann, denn ich habe ja keine TexturKoordinaten vergeben, sondern schreibe die Daten ja "nur" über das Array in die Textur.
uniform sampler2D tex; vec4 test = texture2D(tex, ???);Bei ??? würde ja (wenn ich das richtig verstanden habe) die Texturkoordinate des jeweiligen Vertex stehen. Die müsste ich ja jetzt selbst berechnen. Wäre das z.B. beim ersten Texel
vec2(0.0, 0.0)?
-
Eine Texturkoordinate liegt ja im Bereich [0..1[
Du musst also lediglich den "Index" (0..n) durch die Texturbreite dividieren.
Wenn Deine Textur zb. 64 "Pixel" breit ist, liegt der erste "Pixel" bei (0, 0) der zweite bei (1/64, 0), (2/64, 0), usw.Desweiteren moechtest Du fuer jeden Ausgabe-Pixel die naechste Texturzeile adressieren. Diese Koordinate kannst Du Dir vom Rasterizer interpolieren lassen indem Du Deinem Polygon einfach eine Texturkoordinate mitgibst (rechts=0, links=1).
-
hmm, leider macht mein kleines Programm immer noch nicht das was es soll.
Eine Frage die sich mir z.B. noch stellt:Wenn ich die Textur als einzige Eingabe für den Shader nutze, (und nichts rendere) wird der Vertexshader (oder Geometryshader) doch erst gar nicht verwendet, oder?
Müsste ich ein Quad mit der Textur rendern oder gibts da eine andere elegante Lösung?
-
o.k. die Frage hat sich erledigt

Aber ich hab noch eine Frage praktischer Natur:
ich habe einen Vertex-Shader und einen Geometry-Shader und will einen einfachen Vector erst von OpenGL an den Vertex-Shader, dann vom Vertex-Shader an den Geometry-Shader übergeben.
Nach einigen Tests, scheint aber mindestens die Übergabe zwischen den Shadern schon schief zu laufen:
Vertexshader;
#version 120 uniform vec4 normal; //da kommt was rein varying vec4 var_normal; //das will ich raus schicken void main(void) { gl_FrontColor = gl_Color; gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex; //var_normal = normal; var_normal = vec4(1.0,0.0,0.0,1.0); //fester Wert, zum testen }Geometry-Shader(Snippet):
varying in vec4 var_normal;Leider kommt nix an. Erst wenn ich den Vector im Geometry-Shader mit dem entsprechenden Wert belege, sehe ich ein Ergebnis. Fehlt noch irgendein Schlüsselwort, oder sowas in der Art?
Grüße,
mtx
-
Wenn ich die Textur als einzige Eingabe für den Shader nutze, (und nichts rendere) wird der Vertexshader (oder Geometryshader) doch erst gar nicht verwendet, oder?
Ich weiss jetzt nicht so richtig was meinst.
Wenn Du nichts "renderst", dh keine Vertexdaten schickst, kommt auch der Pixel-Shader zwangslaeufig nicht zum Einsatz.
Wenn Dein Shader ein Vertex-Programm beinhaltet (glAttachObjectARB) laufen Deine Vertexdaten da auch durch, sonst eben durch die Fixed-Function-Pipeline.
In letzterem Fall muss Dein Pixel-Programm die Parameter eben von den vorgeschriebenen "Registern" (zb gl_TexCoord[0].xyzw) lesen.
Persoenlich finde ich es uebersichtlicher, immer ein Vertex-Programm zu benutzen weil die Parameter-Uebergabe zwischen Vertex- & Pixel-Programm einheitlich ist.
Wenn es *gar nicht* das tut was Du erwartest, guckst Du am besten mal in den Error-String vom Shader-Compiler (glGetInfoLogARB).Geometry-Shader(Snippet):
varying in vec4 var_normal;Sehr knappes Snippet

Willst Du denn jetzt Geometry Shader oder Pixel-Shader verwenden?
Im Geometry-Shader gehoert "var_normal" ja zu einem (indizierten) Vertex...
-
hat etwas länger gedauert, aber: es hat doch noch geklappt.
Lag nicht an meinem Code, sondern an einer verwendeten Klasse
Vielen Dank!
-
Hallo zusammen,
ich habe im Moment das Problem, dass ich eine float Variable an meinen Shader übergeben möchte und da irgendwie nichts ankommt.
Dabei gehe ich vor wie im Orange Book und Super Bible beschrieben.
GLint glGetUniformLocation(GLuint program, const char *name); GLint glVertexAttrib{1,2,3,4}fv(GLint location, GLfloat *v);Doch irgendwie bleiben die Objekte komplett schwarz oder weiß.
Der Zugriff darauf findet erst im Fragment-Shader statt. Dort habe ich sie wie folgt definiert;
uniform float fade;In meinen Szenen Prozeduren definiere ich mir jedes Mal diese fade Variable und übergebe diese. Ist diese Vorgehensweise vielleicht falsch? Muss diese Variable vielleicht an einer anderen Stelle definiert werden, in den Beispielen aus den oben genannten Büchern sind diese global definiert, aber unter C++ finde ich das eher unschön?
Mfg
FireballGFX
-
glVertexAttrib{1,2,3,4}fv
Nimm mal lieber glUniform1234fvARB.
-
Hallo zusammen,
wie ist das eigentlich, da ich meine fade Variable im Fragment Shader benötige, kann ich dann einfach per Uniform darauf zugreifen oder muss ich sie im Vertex Shader definieren und zugleich als varying? Wenn ich die Anwendung debugge, dann kommt er auch in den glUniform2fARB Teil. Aber trotzdem scheint im Shader nichts anzukommen. Alle Objekte sind komplett weiß.
C++ Code
GLfloat fade = 0.5f; ... uniformFade = glGetUniformLocation(progObj[LIGHT_SHADER], "fade"); if (uniformFade != -1) { glUniform2fARB(uniformFade, 1, fade); }... uniform float fade; ... void main(void) { float specularExp; if(fade == 0.5f) { specularExp = 89.0; } ...Mfg
Fireball
-
glUniform2fARB
Du schreibst zwei floats an die Position von "fade".
if(fade == 0.5f)Sowas wird haeufig scheitern weil die Praezision der GPU-Register nicht eindeutig festgelegt ist.
-
Super, dass war der Fehler!! Danke dir!