OpenGL Würfel Flächennormalen

Icewurm

Lt. Junior Grade
Registriert
Juli 2006
Beiträge
284
Hallo,

Ich erarbeite mir gerade die Grundlagen für eine kleine Android App.

Ich verwende OpenGL ES 2 für die 3D-Umgebung.

Meine Klasse soll die Vertex- und Indexbufferdaten für ein 3D-Objekt mit n-eckiger Grundfläche, einer bestimmten Seitenlänge und Höhe berechnen und darstellen.

Für die Lichtberechnungen brauche ich jetzt die Flächennormalen.

Beispiel Würfel:

Da ich pro Vertex ja nur einen Vektor speichern kann, dieser aber an 3 Seiten grenzt, in welche Richtung muss der jetzt zeigen?

Aus einem Buch habe ich die Lösung für die Landschaft. Beim Würfel sieht das aber irgendwie falsch aus (siehe Anhang):
Es werden dabei aus den Punkten links und rechts sowie oben und unten vom eigentlichen Eckpunkt Vektoren gebildet und die Normale per Vektorprodukt berechnet.

Hat irgendwer einen Tipp für mich?

Danke.

Michael

Würfel.jpg
 
Dein Problem ist, dass du die normale Normale pro Vertex angibst und für den Fragment-Shader die Normale innerhalb des Dreiecks zwischen den 3 Normalen der Vertexe interpoliert wird. Auf diese Weise vermeidet man, dass zwischen den Dreiecken harte Kanten sichbar werden (siehe https://upload.wikimedia.org/wikipedia/commons/8/84/Phong-shading-sample.jpg) - aber in manchen Fällen so wie bei dir - möchte man dennoch harte Kanten zeichnen. Die Standard-Lösung in diesem Fall ist es bei harten Kanten die entsprechenden Positionen mehrmals ins Vertexarray aufzunehmen, allerdings mit jeweils einer anderen Normale. Auf diese Weise ist die Normale innerhalb des Dreiecks konstant, wodurch sich beim Shading harte Kanten ergeben.
 
D.h. ich speichere jeden Eckpunkt 3 mal, setzte die Indices darauf und berechne die Normalen dann einmal pro Fläche und speichere sie dann zu allen 4 Vertices? (pro Seite)
 
Dadurch hast du allerdings einen overhead: Für einen Würfel speicherst du 24 statt acht Vertices. Um das zu vermeiden bietet OpenGL index buffer. Mit denen speicherst du einmal die zB acht vertices und in dem index buffer dann nur die indizes für die entsprechende Seite. Genauer wird das ganze hier erklärt.

Ich hab die Daten auch noch hier als Java Code für einen Cube von -1 bis +1 um den Ursprung, die Seiten sind Triangles:
Code:
public final class StaticData {

	public static final float[] CUBE_VERTICES = {
		-1, -1, -1,
		-1, -1, 1,
		-1, 1, -1,
		-1, 1, 1,
		1, -1, -1,
		1, -1, 1,
		1, 1, -1,
		1, 1, 1,
	};

	public static final short[] CUBE_INDICES = {
		0, 5, 1,
		0, 4, 5,
		1, 5, 3,
		3, 5, 7,
		5, 4, 7,
		7, 4, 6,
		4, 0, 2,
		2, 6, 4,
		3, 0, 1,
		3, 2, 0,
		3, 7, 2,
		2, 7, 6,
	};

	public static final float[] CUBE_TEX_3D = {
		0, 0, 0,
		0, 0, 1,
		0, 1, 0,
		0, 1, 1,
		1, 0, 0,
		1, 0, 1,
		1, 1, 0,
		1, 1, 1,
	};

	private StaticData() {}

}
 
@ NemesisFS
So wie du es gemacht hast, hat es der TE ja zu beginn auch gemacht, weshalb er auch Probleme mit seinen Normalen hatte. Selbst dein Link schlägt bei harten Kanten so wie ich vor den Vertex zu duplizieren.

Eventuell zur Ergänzung noch ein paar andere Ansätze außer dem was ich vorhin gesagt habe. Diese Ansätze liefern aber überall harte Kanten und sind nicht ganz so einfach zu implementieren:
-Rekonstruktion der Normale aus den Eckpunkten im Geometry-Shader
-Rekonstruktion der Normale im Fragmentshader über Gradientenoperatoren auf der Position des Fragments
-Rekonstruktion im Postprocessing aus dem Tiefenbild

Alternativ könnte man beim Zeichnen des Würfels auch ein glDrawArrays verwenden, weil jeder Index im Indexbuffer sowieso nur einmal vorkommt.

P.S. Dein Würfel sieht sehr nach Proxy Geometrie für Volumenrendering aus ;)
 
Zuletzt bearbeitet:
Wobei ich die Ansätze alle für nicht sehr praktikabel halte, weil man gleich den Shader wechseln muss, um mit demselben Material dann doch mal wieder etwas Rundes zu rendern.

Dadurch hast du allerdings einen overhead:
Die Welt wird von den paar doppelten Vertices nicht untergehen. Braucht minimal mehr Speicher (im Vergleich zu großen Texturen ist das... nichts) und ein paar mehr Vertex Shader-Invocations (...im Vergleich zum Fragment Shader ist aber auch das nichts).

Alternativ könnte man beim Zeichnen des Würfels auch ein glDrawArrays verwenden, weil jeder Index im Indexbuffer sowieso nur einmal vorkommt.
Wenn er ganz normal mit Dreiecken rendert, hat er zwei Indizes pro Fläche doppelt - nen Primitive Restart Index gibbet bei GL ES ja nicht, Triangle Strips fallen damit auch mehr oder weniger flach (wenn man nicht gerade Draw Calls für jeweils zwei Dreiecke machen will :freak:).
 
Nai schrieb:
P.S. Dein Würfel sieht sehr nach Proxy Geometrie für Volumenrendering aus ;)
Exakt ;-) Da kammen später MRI scans rein.
VikingGe schrieb:
Die Welt wird von den paar doppelten Vertices nicht untergehen. Braucht minimal mehr Speicher (im Vergleich zu großen Texturen ist das... nichts) und ein paar mehr Vertex Shader-Invocations (...im Vergleich zum Fragment Shader ist aber auch das nichts).
Das stimmt, in dem konkreten Fall machen die paar Vertices nichts. Ich wollte nur die Alternative aufzeigen. Zugegebenermaßen habe ich übersehen, dass das die ursprüngliche Idee des TEs war.
 
GL_QUADS, ja, das war noch was. Wenn man harte Kanten haben wollte, machte man per
Code:
glShadeModel(GL_FLAT);
Flat Shading an, und per
Code:
glShadeModel(GL_SMOOTH);
schaltete man wieder auf Gouraud Shading. Und Phong Shading gab's nicht, bzw. man konnte es sich etwas später per Pixel Shader selbst programmieren (hab ich mal mit GLSL gemacht, k.A. wie performant das war).

Wer den Unterschied zwischen Gouraud und Phong Shading nicht kennt (sieht ja beides fast gleich aus): bei Gouraud wird nur der Helligkeitswert interpoliert, bei Phong dagegen der Normalenvektor, über den der Helligkeitswert berechnet wird.
 
Zurück
Oben