OpenGL: Zuweisung von Daten zu Shaderprogramm?

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Elmi
Beiträge: 12
Registriert: 13.06.2023, 07:30

OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von Elmi »

Hi,

ich habe offenbar noch ein Grundlegendes Verständnisproblem, was die Zuweisung von Daten zu den Parametern im Shaderprogramm angeht.

Bisher habe ich in meiner Applikation nur Wireframes dargestellt: glPolygonMode(GL_FRONT_AND_BACK,GL_LINE) und das Shaderprogramm war extrem simpel:

Code: Alles auswählen

#version 130
uniform vec4 inputColor;
out vec4 fragment_color;
void main() {
   fragment_color=inputColor;
}\0
Die Koordinaten wurden dann einfach mit Hilfe der Indexposition 0 übergeben, was offenbar klappt, da es außer den 3D-Koordinaten nichts weiter gibt:

Code: Alles auswählen

glBindVertexArray(entity->m_gl3Element.VAO);
glBindBuffer(GL_ARRAY_BUFFER,entity->m_gl3Element.coordVBO);
glBufferData(GL_ARRAY_BUFFER,m_vertexArray.size()*sizeof(float),m_vertexArray.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Jetzt möchte ich aus meinem Wireframe aber eine Solid-Darstellung machen (glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)), heißt also, ich benötige zusätzlich Licht und Normals. Der neue Shader sieht dann so aus:

Code: Alles auswählen

#version 130
in vec3 Normal;
in vec3 fpos;

out vec4 fragment_color;

const vec3 lightPos = vec3(0.0,0.0,5.0);
const vec3 diffColor = vec3(1.0,0.5,0.0);
const vec3 specColor = vec3(1.0,1.0,1.0);

void main () {
 vec3 normal = normalize(Normal);
 vec3 viewDir = normalize(-fpos);
 if (dot(normal, viewDir) < 0.0) normal *= -1.0;

 vec3 lightDir = normalize(lightPos - fpos);
 float lamb = max(dot(lightDir, normal), 0.0);
 float spec = 0.0;

 if (lamb > 0.0) {
  vec3 refDir = reflect(-lightDir, normal);
  float specAngle = max(dot(refDir, viewDir), 0.0);
  spec = pow(specAngle, 4.0);
 }
fragment_color = vec4(lamb * diffColor + spec * specColor, 1.0);
}\0";
Zusätzlich müssen die Normals übergeben werden:

Code: Alles auswählen

glBindBuffer(GL_ARRAY_BUFFER,entity->m_gl3Element.normalVBO);
glBufferData(GL_ARRAY_BUFFER, normalArray.size()*sizeof(float),normalArray.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER,entity->m_gl3Element.normalVBO);
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(void*)0);
Und genau das funktioniert nicht, weil offenbar die Zuweisung zwischen den Normal-Daten (Indexwert 1) und dem Parameter "Normal" aus dem Shader nicht klappt, das Objekt ist nach wie vor komplett schwarz. glGetAttribLocation(program, "Normal") liefert immer eine -1 zurück (wird wohl von dieser OpenGL-Version noch nicht unterstützt) und ein "layout(location=1) in vec3 Normal" im Shader compiliert nicht.

Deswegen meine Frage: wie funktioniert das, wie kann ich die Normals korrekt und eindeutig zuweisen?

Danke!
Matthias Gubisch
Establishment
Beiträge: 470
Registriert: 01.03.2009, 19:09

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von Matthias Gubisch »

Keine grosse Ahnung von OGL aber ein paar tips/fragen.

1. "layout(location=1) in vec3 Normal" kompiliert nicht, warum? Was ist die Fehlermeldung?
2. Wie sieht denn der vertex shader aus?
3. Lass doch mal deine Berechnungen alle weg und setze als output farbe entweder die position oder die normalen, damit kannst du sehen ob deine Daten korrekt im vertex shader gelesen und an den fragment shader gegeben werden.
4. In deinem unteren code nutzt du einmal glBufferData und einmel glVertexAttribPointer das sieht fuer mich irgendwie seltsam aus, aber vielleicht liegt das auch an meinen fehlenden OGL Kenntnissen
Bevor man den Kopf schüttelt, sollte man sich vergewissern einen zu haben
mtorc1
Beiträge: 80
Registriert: 20.02.2021, 16:24

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von mtorc1 »

*Doppelpost
Zuletzt geändert von mtorc1 am 13.06.2023, 12:06, insgesamt 1-mal geändert.
Letztes Projekt: Grave of the Pumpkin (ZFX Halloween Action 2021)
mtorc1
Beiträge: 80
Registriert: 20.02.2021, 16:24

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von mtorc1 »

Hi,

in dem Kontext ist es sehr sinnvoll mit glGetAttribLocation() den tatsächlich benutzten Index abzufragen. Die Dokumentation gibt einen Hinweis, warum du aber "-1" zurückkriegst:
If the named attribute variable is not an active attribute in the specified program object or if name starts with the reserved prefix "gl_", a value of -1 is returned.
Das lässt sich von deinen Code-Schnipseln nicht rekonstruieren, aber das klingt, als würdest du auf den Normalenvektor erst im Fragment Shader zugreifen ohne ihn vom Vertex Shader aus durchzureichen.

Ansonsten:
Das hier vermeidet bei der Wireframe-Darstellung, dass die Rückseiten schwarz sind und es trotzdem "irgendwie" beleuchtet ausschaut. Bei solid faces und erst recht ohne alpha blending kannst du das weglassen und dann auch den cull mode auf GL_FRONT setzen.

Code: Alles auswählen

 vec3 viewDir = normalize(-fpos);
 if (dot(normal, viewDir) < 0.0) normal *= -1.0; 
 
Gruß!
Letztes Projekt: Grave of the Pumpkin (ZFX Halloween Action 2021)
joeydee
Establishment
Beiträge: 1044
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von joeydee »

Schließe mich der Einschätzung an, es sieht aus als sei "in vec3 Normal" im Fragment-Shader definiert? Das sind Vertex-Attribute, werden also im Vertex-Shader gesucht. Definiere das mal dort, und schau ob er dann die Location findet.
Falls ja, musst du das wie schon erwähnt einfach an den Fragmentshader durchreichen, im Fragmentshader kommt dann der interpolierte Wert aus den 3 Vertexwerten des aktuellen Dreiecks an, daher ist dieses "Durchreichen" notwendig.
Elmi
Beiträge: 12
Registriert: 13.06.2023, 07:30

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von Elmi »

OK, dann will ich mal einen Schritt zurückgehen: Bei meiner bisherigen, funktionierenden Wireframe-Lösung habe ich folgenden Vertexshader:

Code: Alles auswählen

#version 130
in vec3 aPos;
uniform mat4 inputTransform;
flat out vec3 startPos;
out vec3 vertPos;
void main() {
   vec4 pos=inputTransform * vec4(aPos, 1.0);
   gl_Position=pos;
   vertPos=pos.xyz / pos.w;
   startPos=vertPos;
}\0
...und diesen Fragmentshader verwendet:

Code: Alles auswählen

#version 130
uniform vec4 inputColor;
out vec4 fragment_color;
void main() {
   fragment_color=inputColor;
}\0
Bei diesen hat die Datenübergabe per Index 0 wohl nur deswegen problemlos geklappt, weil es nur Geometriedaten gab und sonst nix.

Den neuen Fragmentshader aus meiner Ursprungsfrage oben habe ich einem Tutorial entnommen, dass diese Normals-Geschichte erklärt hat - wobei ich den Vertexshader unverändert gelassen habe (das Tutorial hat nur vom Fragmentshader gesprochen).

"layout(location=1) in vec3 Normal" compiliert bei mir nicht mit der Fehlermeldung

Code: Alles auswählen

Fragment shader failed to compile with the following errors:
ERROR: 0:2: error(#5) Extension: "explicit location is not supported in this version"
...was ich wiederum so interpretiere, dass es dieses Statement in der Shaderlanguage Version 130 schlichtweg noch nicht gibt. Heißt, ich benötige irgend einen anderen Weg, um auf die zu verwendenden Indexwerte zu kommen!?
Benutzeravatar
Jonathan
Establishment
Beiträge: 2370
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von Jonathan »

Die OpenGL API ist frickelig und altmodisch, deswegen empfiehlt es sich Tools wie nVidia nSight zu lernen. Das zeigt dir nicht nur Fehlermeldungen an, sondern du kannst auch den exakten State nachschauen, also z.B. welcher Buffer an welches Attribut gebunden ist und so. Der Einstieg ist nicht ganz einfach, aber es lohnt sich auf jeden Fall. Selbst mit nSight bleibt OpenGL noch frickelig, aber es ist halt zumindest besser.
glGetAttribLocation(program, "Normal") liefert immer eine -1 zurück (wird wohl von dieser OpenGL-Version noch nicht unterstützt) und ein "layout(location=1) in vec3 Normal" im Shader compiliert nicht.
Welche Version benutzt du denn? Selbst die neuste (4.5 oder so) ist ja schon einige Jahre alt, kannst oder willst du die nicht benutzen?

Ein genereller Tipp noch: Reduziere Komplexität. Mach nicht direkt Lichtberechnung, sondern setze die Farbe erstmal auf die Normale. Dann siehst du ob die Normalvektoren richtig ankommen. Wenn du direkt Lichtberechnung machst kann schwarze Farbe entweder bedeuten, dass deine Normalen kaputt sind, oder dass deine Lichtberechnung kaputt ist, also weißt du nicht, wo der Fehler liegt. Deshalb lieber ganz langsam ein Feature nach dem anderen Hinzufügen und nach jedem Schritt testen.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
mtorc1
Beiträge: 80
Registriert: 20.02.2021, 16:24

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von mtorc1 »

Elmi hat geschrieben: 13.06.2023, 13:09 Den neuen Fragmentshader aus meiner Ursprungsfrage oben habe ich einem Tutorial entnommen, dass diese Normals-Geschichte erklärt hat - wobei ich den Vertexshader unverändert gelassen habe (das Tutorial hat nur vom Fragmentshader gesprochen).
Eben das! Du kannst Vertex(!)-Attribute per se nur an den Vertexshader weitergeben, nicht an den Fragmentshader. Das heißt du brauchst sowas:

Code: Alles auswählen

#version 130
in vec3 aPos;
in vec3 aNormal; // <-- neues Vertex Attribut
uniform mat4 inputTransform;
flat out vec3 startPos;
out vec3 vertPos;
out vec3 vertNormal; // <-- zum Weitergeben an den FragmentShader
void main() {
   vec4 pos=inputTransform * vec4(aPos, 1.0);
   gl_Position=pos;
   vertPos=pos.xyz / pos.w;
   startPos=vertPos;
   vertNormal = aNormal; // <-- Weitergabe; entsprechend im FS auch "vertNormal" benutzen!
}\0
Letztes Projekt: Grave of the Pumpkin (ZFX Halloween Action 2021)
joeydee
Establishment
Beiträge: 1044
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von joeydee »

Genau was ich sagte: Vertex Attribut geht nur im VS und muss an den FS durchgereicht werden. Also du *musst* den VS ändern. Dann sollten auch die Locations per Name gefunden werden. Du kannst *nicht* Vertexattribute im Fragmentshader definieren.
Grund (grob beschrieben):
Je Vertex (inkl. Attributen, wie Farbe, Texcoords, Normale, ...) wird der VS ausgeführt. Dann gibts einen unsichtbaren Zwischenschritt, wo je 3 Verts zu einem Dreieck zusammengefasst werden. Pro Bildschirmpixel in diesem Dreieck wird dann der FS ausgeführt. Damit bekommt jedes FS-Pixel die interpolierten Daten aus den zugehörigen 3 Vertex-Attributen. Und greift nicht auf einen einzigen bestimmten Vertex zu, das wäre ja auch gar nicht eindeutig.
Ich kann später evtl. nochmal kompletten VS/FS-Code nachreichen.
Elmi
Beiträge: 12
Registriert: 13.06.2023, 07:30

Re: OpenGL: Zuweisung von Daten zu Shaderprogramm?

Beitrag von Elmi »

mtorc1 hat geschrieben: 13.06.2023, 13:28 Eben das! Du kannst Vertex(!)-Attribute per se nur an den Vertexshader weitergeben, nicht an den Fragmentshader.
OK, jetzt habe ich es verstanden :-D

Mit der Änderung ist mein Modell jetzt zwar gar nicht mehr zu sehen, aber ich sehe zumindest die Zusammenhänge und weiß jetzt, wo ich weiter suchen kann. Danke!
Antworten