[3D Technik]Normalen berechnen

Parallan

Cadet 3rd Year
Registriert
Okt. 2006
Beiträge
40
Ich versuch mit C++ und OpenGL ein Model in eine Szene zu laden, in der auch Licht gerendert wird. Dazu brauch ich die Normalen des Models beim Erstellen der Liste (die leider nicht in der Model-Datei enthalten sind), nach kurzer Suche hab ich folgende Methode gefunden (grob vereinfacht):
Code:
vertex CalcNormal(vertex v1, vertex v2, vertex v3)
{
    vertex temp_v1, temp_v2, temp_normal;
    temp_v1 = v1-v0;
    temp_v2 = v2-v0;
    temp_normal = crossproduct(temp_v1, temp_v2);
    return normalize(temp_normal);
}
Das funktioniert auch alles, bis auf die Kleinigkeit, dass manche Normalen genau falsch rum sind, was zu Fehlern bei der Beleuchtung führt (bei Quadraten ist bei einem Dreieck die Normale Richtig, die andere Falsch).

Wenn ich Culling in OpenGL anschalte, ist alles korrekt (also, die Dreiecke sind alle im Uhrzeigersinn), außer der Beleuchtung.

Die eigentlich Frage ist: wie kann ich prüfen, ob die Normale in die richtige Richtung zeigt?
(meine Idee: man rendert das Dreieck aus Richtung der Normalen und prüft, ob es im Uhrzeigersinn gedreht ist (mir Fehlen leider die Techniken, um eine Methode zu erstellen, bzw. die bisherigen haben nicht funktioniert))

Parallan
 
Ich empfehle dir, einen Blick auf folgende Algorithmensammlung zum Thema Dreiecke / Polygone zu werfen: http://www.gamedev.net/reference/articles/article425.asp

Die Lösung des Problems der Beurteilung der "Ausrichtung" eines Dreiecks im zweidimensionalen Raum ist in der Funktion "determinant" beschrieben, im 3d-Raum funktioniert es natürlich genauso. Wenn dein Dreieck also die "falsche" Ausrichtung hat (welche das ist kann ich nicht wissen, da ich deinen Shadercode nicht kenne, normalerweise ist die richtige Ausrichtung aber "im Uhrzeigersinn"), änderst du einfach das Vorzeichen des Normalvektors um.

Ich empfehle aber prinzipiell nicht, die Berechnung der Normalen zur Laufzeit des Programms zu machen, da ein Modell mit einer großen Polygonzahl leicht zum Flaschenhals deiner Engine werden kann (ich nehme an, dass du an einem Spieleprojekt arbeitest, ansonsten spielt dies natürlich keine Rolle) und du dir damit die Möglichkeit nimmst, durch gezielte Modifikation der Normalen auf performanceneutralem Weg zusätzliches Detail in dein Modell zu integrieren.

LG
Alexander
 
Und genau deswegen muss man Renderern sagen, in welcher Reihenfolge der Punkte das Dreieck aufgespannt wird (clockwise, counter-clockwise).

Bei Backface-Culling entscheidet ja diese Angabe, ob sichtbar oder nicht. Für die Beleuchtung reicht ja die Richtung des Vektors, da ja der Winkel Lichtquelle:Face interessant ist.


Man könnte jetzt nach folgendem Algorithmus gehen:
1. Mittelpunkt des Körpers z.B. durch Bounding-Box finden M(x,y)
2. Dreieckspunkte P1,P2,P3 hernehmen und neue Vektoren (V1,V2,V3) zu M bilden
3. Winkel zur berechneten Normalen ermitteln
4. Anhand des Winkels kannst Du dann ermitteln, ob Du die Normale im Richtungssinn ändern musst oder nicht

Dann sollten alle Normalen nach außen zeigen.
 
@ AlexandeKappner: Danke für den Link, aber wie man prüft, ob ein Dreieck im Uhrzeigersinn gedreht ist, wusste ich schon (nur, dass die Methode von dir besser ist^^). Das Problem ist, wie ich die Dreiecks Koordinaten so transformieren kann, dass ich sie aus Sicht des (falsch oder richtig) berechneten Normalenvektors sehen kann (und dann die Drehrichtung prüfen). (Und: ich würde es dann sicher nicht während der Laufzeit des Programm berechnen, entweder beim Laden, oder in ein neues Modelformat schreiben)

@ XunnD: Danke für deine Mühen, die Methode würde im groben zwar funktionieren, wenn ich aber in der Modeldatei (zum Beispiel) 2 Zylinder nebeneinander hab, werden die Flächen, die zum Nullpunkt des Models zeigen, falsch berechnet.


@ AlexandeKappner: Hab deinen Beitrag trozdem mal ausprobiert, wenn ich auf allen drei Achsen prüfe, ob das Dreieck im Uhrzeigersinn gedreht ist, und mit der entsprechenden Normalen-Achse vergleich (X-Y Ebene im Vergleich mit der Z-Komponente der Normalen), funktionierts. Also, danke nochmal für die Idee.
 
Zuletzt bearbeitet: (Hinzufügen der letzten Antwort)
Zurück
Oben