[OpenGL] Beleuchtung

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
joggel

[OpenGL] Beleuchtung

Beitrag von joggel »

Hallo ZFXler,

ich bin so ein verdammter Mathe-Legastheniker :(
Deswegen brauch ich hier mal etwas Hilfe.

Ich bin dabei Licht in meine 3D-Welt zu implementieren.
Ich habe mir dazu mal eine provisorische Landschaft geniert.
Anzeige funktioniert.

Nun habe ich durch Tutorials und etwas WWW-Suche mir einen Shader zurecht gebastelt.

Vertex-shader:

Code: Alles auswählen

#version 330 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec3 normalVec;

uniform mat4 cameraView;			// model-view-matrix
uniform mat4 projektionsMatrix;		// projektions-matrix 
uniform mat4 model;					// model-matarix des Objektes
uniform mat4 mvpMatrix;				// model-view-projektions-matrix

out vec3 fragNormal;
out vec3 fragVert;

void main()
{
	gl_Position =  projektionsMatrix * cameraView * model * vec4(vertexPosition,1);
	fragVert.xyz = gl_Position.xyz;
	fragNormal = normalVec;
}
Fragment-Shader:

Code: Alles auswählen

#version 330 core

uniform struct Light
{
   vec3 position;
   vec3 intensities; //a.k.a the color of the light
} light;

in vec3 fragNormal;
in vec3 fragVert;
uniform mat4 cameraView;			// model-view-matrix der Kamera
uniform mat4 projektionsMatrix;		// projektion-matrix
uniform mat4 model;					// model-matrix des Objektes
uniform mat4 mvpMatrix;				// model-view-projektions-matrix

// Ouput data
out vec4 finalColor;

void main()
{
	//calculate normal in world coordinates
	mat3 normalMatrix = transpose(inverse(mat3(cameraView)));
	vec3 normal = normalize(normalMatrix * fragNormal);

	//calculate the location of this fragment (pixel) in world coordinates
	vec3 fragPosition = vec3(model * vec4(fragVert, 1));

	//calculate the vector from this pixels surface to the light source
	vec3 surfaceToLight = light.position - fragPosition;

	//calculate the cosine of the angle of incidence
	float brightness = dot(normal, surfaceToLight) / (length(surfaceToLight) * length(normal));
	brightness = clamp(brightness, 0, 1);

	//calculate final color of the pixel, based on:
	// 1. The angle of incidence: brightness
	// 2. The color/intensities of the light: light.intensities
	// 3. The texture and texture coord: texture(tex, fragTexCoord)
	vec4 surfaceColor = vec4(0.5, 0.2, 0.8, 1.0);
	finalColor = vec4(brightness * light.intensities * surfaceColor.rgb, surfaceColor.a);
}
Die Beleuchtung funktioniert, nur bewegt sich das Licht mit der Camera mit, was ich nun überhaupt nicht möchte.
Leider verstehe ich kaum die ganze Mathematik dahinter und wäre froh wenn mir mal jemand erklärt (für Doofies)
wie das gemacht wird...
kristof
Beiträge: 91
Registriert: 19.01.2009, 13:05

Re: [OpenGL] Beleuchtung

Beitrag von kristof »

Im Vertex Shader multiplizierst du die Vertex Position mit der Projektionsmatrix, Viewmatrix und Modelmatrix. Das transformiert die Vertex Position in Normalized Device Coordinates. Das braucht OpenGL um effizient entscheiden zu können ob etwas sichtbar ist und welche Fragmente von einem Face tatsächlich betroffen sind.
Für deine Lichtberechnungen ist das jedoch nicht hilfreich, da bei der Multiplikation mit der Projektionsmatrix der Raum verzerrt wird. Zumindest wüsste ich nicht, wie man in NDCs Licht berechnen könnte.
Du solltest dir also überlegen deine Lichtberechnungen entweder im Welt-Koordinatensystem (World space) oder im Kamera-Koordinatensystem (View space) zu berechnen.
Eine Multiplikation mit der Modelmatrix bringt dich in das Welt-Koordinatensystem. Wenn du das Ergebnis dann noch mit der Viewmatrix multiplizierst bist du im Koordinatensystem der Kamera.

Du könntest also z.B. um das Licht im Kamera-Koordinatensystem zu berechnen im Vertex Shader folgendes tun:

Code: Alles auswählen

vec4 viewPosition = cameraView * model * vec4(vertexPosition,1);
gl_Position = projektionsMatrix * viewPosition;
fragVert.xyz = viewPosition.xyz;
Im Fragment Shader musst du dann natürlich noch sicher stellen, dass deine Lichtposition auch im Koordinatensystem der Kamera ist. Wenn du also die Position des Lichtes in Welt Koordinaten hast, dann musst du die Position vor der Übergabe an den Shader noch mit der Viewmatrix multiplizieren.

Noch eine Sache, die nicht direkt mit deinem Problem zu tun hat, aber für später vielleicht auch gut zu Wissen ist:
Wenn man eine Berechnung nicht im Shader machen muss, weil das Ergebnis für alle Durchläufe des Shaders immer gleich ist sollte man es schon auf der CPU berechnen. Das ist eigentlich immer schneller. Die Multiplikation von View- und Modelmatrix wäre so eine Sache. Und noch deutlich kritischer, da momentan im Fragment Shader: Die Berechnung der Normalmatrix.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [OpenGL] Beleuchtung

Beitrag von dot »

Ist eigentlich ziemlich einfach. Dein Shader implementiert simples "n dot l" Shading, welches auf dem Lambertschen Gesetz basiert: Angenommen du hast eine perfekt diffus reflektierende Oberfläche (d.h. alles einfallende Licht wird perfekt gleichmäßig in alle Richtungen zerstreut), dann ist die von einem auf die Oberfläche blickenden Betrachter wahrgenommene Helligkeit
  • unabhängig von der Position des Betrachters (weil ja in alle Richtungen die gleiche Menge Licht abgestrahlt wird) und
  • proportional zum Kosinus des Winkels in dem das Licht auf die Oberfläche fällt.
Letzterer Punkt macht z.B. nach Betrachtung folgendes Bildes (von hier)
Bild
auch intuitiv Sinn: Wenn die gleiche Lichtmenge unter einem Winkel \(\theta\) einfällt, verteilt sie sich auf eine im Vergleich zum senkrechten Einfall um den Faktor \(\frac{1}{\cos\theta}\) größere Fläche. Das Punktprodukt von Normalvektor (in der Regel mit n bezeichnet) und Lichteinfallsvektor (in der Regel mit l bezeichnet) liefert (im Falle dass beide normalisiert sind) den Kosinus des Winkels. Ein sehr einfaches, effektives und extrem effizient berechenbares Beleuchtungsmodell...

Edit: Ist \(\LaTeX\) kaputt?
Zuletzt geändert von dot am 21.08.2015, 10:51, insgesamt 1-mal geändert.
joggel

Re: [OpenGL] Beleuchtung

Beitrag von joggel »

@kristof
ich bün hoch erfreut. Es fünktionürt :)
Vielen vielen Dank!!!

@dot
danke für die Erklärung.
und was mit LaTeX ist weiß ich auch nicht...
Antworten