OpenGL: Seltsames Licht-Verhalten nach glScale(). Es "dreht durch", obwohl es das eig. garnicht kann!
-
Hallo,
Ich grübel hier schon etwas länger über ein seltsames Verhalten... Vielleicht kann mir hier jamend erklären was da los ist.
Hier erstmal mein 'Versuchsaufbau':Im Init:
-smooth shading
-Licht an
-Licht-Position setzenIn Renderfunktion:
-Clear Color
-LoadIdentity
-Scale(1,1,0) <----"0" scheint die Ursache zu sein...
-Quad zeichnen, (Pseudo-)Normale = (1,1,1); (Richtung/Länge unerheblich!)
-LoadIdentity
-Rotate( angle(time), 1,0,0 )
-SwapBuffersSo, das ist der Ablauf!
Das Problem ist jetzt aber, dass sich das Licht zu drehen scheint... Sprich jedes Vertex des Quad ändert nach und nach seine Farbe! Und das hat eindeutig was mit dem Rotate zutun. Obwohl es nach allem anderen kommt...!Kann mir bitte jemand sagen, was hier los ist??! Ich habe das Gefühl, mein Kopf platzt bald, aber ich kann mir darauf einfach keinen Reim machen..
Ein Scale(..0..) kat keinem Vertex geschadet, aber der Beleuchtung scheint das nicht gut zu bekommen.
Also ich vermute, das ist nicht normal. Ich wüsste aber trotzdem, warum das so ist, bzw. was OpenGL da unter der Haube veranstaltet, dass dieses Verhalten dabei raus kommt...
...Und ich dachte schon, ich hätte OpenGL verstanden...Gruß
OpenGl-Fifi
-
OpenGl-Fifi schrieb:
-Quad zeichnen, (Pseudo-)Normale = (1,1,1); (Richtung/Länge unerheblich!)
Die Richtung der Normalen ist für die Beleuchtungsberechnung mitnichten unerheblich. Natürlich sollte die Normale orthogonal zur Fläche zeigen, für die sie definiert ist. Für ein Quad das parallel zur Bildebene liegt ist das z.B.
Ferner hast du eine Skalierung in Z-Richtung von 0. Die Normalen üblicherweise gesondert mit der transponierten inversen der Transformationsmatrix transformiert. Bei einer Skalierung auf 0 ist diese inverse Transformation allerdings nicht definiert (das ist, als wollte man nach auflösen). Ich denke das trägt zu dem Problem bei.
Ich würde auf die 0-Skalierungstransformation verzichten (man kann z.B. stattdessen die z-Koordinaten der Vertices direkt auf 0 setzen, damit erzielt man dasselbe Resultat) und natürlich die Normale orthtogonal zum Quad definieren.
Finnegan
-
und glEnable(GL_NORMALIZE) nicht vergessen wenn skalierungen im spiel sind.
-
Nabend,
Danke für eure Tipps. ...Aaaber, ich hätte da doch noch ne Frage..Die Richtung der Normalen ist für die Beleuchtungsberechnung mitnichten unerheblich.
Das das nicht der richtige Normalenvektor ist, was Richtung und Länge angeht, ist klar. Der ist vielmehr extra so schief, damit ich durch die Achsen-Skalierung nicht zufällig einen Nullvektor erhalte.
Das Problem ist ja auch nicht, dass es zu hell oder zu dunkel ist, sondern, dass es sich mit der Zeit ändert.. Und zwar entsprechend der 'Rotationsfrequenz'.
Und das, obwohl nach der Rotation keine weiteren Anweisungen mehr folgen. Das ist ehrlich gesagt, das, was ich am wenigsten verstehe. Denn bis Rotate kommt, sollten eigentlich schon alle Lichtberechnungen durchgeführt worden sein - dachte ich...
Offensichtlich falsch gedacht! Aber wie ist es dann richtig?!Die Normalen üblicherweise gesondert mit der transponierten inversen der Transformationsmatrix transformiert.
Woher weißt du das?
Ich verstehe nicht wirklich den Sinn dahinter. Normalerweise wird ja jeder Vektor (Vertex/Normale) mit der Trafo-Matrix transformiert, um seine endgültigen Koordinaten zu erhalten. Also:v' = M v
Und nun soll es
v' = (M(-1))T v
sein, wenn ich dich richtig verstehe? Warum das?
-
OpenGl-Fifi schrieb:
Nabend,
Danke für eure Tipps. ...Aaaber, ich hätte da doch noch ne Frage..Die Richtung der Normalen ist für die Beleuchtungsberechnung mitnichten unerheblich.
Das das nicht der richtige Normalenvektor ist, was Richtung und Länge angeht, ist klar. Der ist vielmehr extra so schief, damit ich durch die Achsen-Skalierung nicht zufällig einen Nullvektor erhalte.
Ah...verstehe. Erstmal irgendeine Normale, damit man überhaupt etwas sieht (?).
OpenGl-Fifi schrieb:
Das Problem ist ja auch nicht, dass es zu hell oder zu dunkel ist, sondern, dass es sich mit der Zeit ändert.. Und zwar entsprechend der 'Rotationsfrequenz'.
Und das, obwohl nach der Rotation keine weiteren Anweisungen mehr folgen. Das ist ehrlich gesagt, das, was ich am wenigsten verstehe. Denn bis Rotate kommt, sollten eigentlich schon alle Lichtberechnungen durchgeführt worden sein - dachte ich...
Offensichtlich falsch gedacht! Aber wie ist es dann richtig?!jetzt, wo du mich nochmal mit der Nase drauf stößt, fällt es mir auch auf. Ich bin ehrlich gesagt nicht so bewandert in der Fixed Function Pipeline, aber nach meinem Verständnis sollte die Rotation eigentlich gar keine Auswirkung haben, da du bei einem erneuten Render-Aufruf wieder die Identitätsmatrix setzt. Seltsam. Das ist ein ganz normales glRotate() und es sind auch keine glMatrixMode()-Anweisungen irgendwo dazwischen? Die gesammte Beleuchtung sollte eigentlich im "Quad zeichnen" ablaufen.
OpenGl-Fifi schrieb:
v' = M v
Und nun soll es
v' = (M(-1))T v
sein, wenn ich dich richtig verstehe? Warum das?
Ja allerdings nur für die Normalen! Diese kann man nicht einfach genau so transformieren wie die Vertices. Am einfachsten ist das zu verstehen wenn man sich die Translation anschaut: Angenommen ich habe ein Objekt mit sauber definierten Normalen und verschiebe das Objekt bis weit hinter Timbuktu.
Was passiert mit den Normalen wenn man auf diese die selbe Transformation anwendet? Die werden furchtbar langgezogen und verändern dabei ihren Winkel!
Das sind sicher nicht mehr die korrekten Normalen für dein Objekt, denn diese sollten sich ja bei einer reinen Translation nicht verändern.
Ebenso verhält es sich mit einer nicht-uniformen Skalierung: Stell dir eine Kugel vor, bei der die Normalen schön igelförmig orthogonal zur Kugeloberfläche stehen. Wenn ich die Kugel nun von "oben" zu einem Ellipsoid plattdrücke, indem ich z.B. nur entlang der Y-Koordinate um z.B. 0.5 skaliere, vergrößert sich der Winkel zwischen Normalen und Y-Achse, wenn ich diese genau so "plattdrücke". Dabei sollte es eigentlich umgekehrt sein - da die Krümmung des Ellipsoids an ober- und Unterseite geringer ist, als die der Kugel, sollte der Winkel zwischen Normalen und Y-Achse eigentlich geringer geworden sein.
Reine Rotationen dagegen sind in Ordnung. Die sollen die Normalen genau so mitmachen wie die Vertices.
Ich habe die Herleitung/Beweis nicht aus dem Gedächtnis parat (sollte sich leicht im Netz finden lassen) aber für eine allgemeine affine Transformation ist die korrekte Transformation der Normalen . Ich speichere für komplexere Objekttransformationen oft auch eine zusätzlich noch eine solche -Matrix. Diese kann man leicht "mitführen", indem man die "umgekehrte" Operation "von rechts" aufmultipliziert, z.B. bei einer Rotation um die x-Achse um :
Das spart später das etwas teurere invertieren (besonders wenn man es für sehr viele Objekte mindestens 60 mal pro Sekunde macht)
Gruss,
Finnegan
-
Ah...verstehe. Erstmal irgendeine Normale, damit man überhaupt etwas sieht (?).
Genau.
Das ist ein ganz normales glRotate() und es sind auch keine glMatrixMode()-Anweisungen irgendwo dazwischen? Die gesammte Beleuchtung sollte eigentlich im "Quad zeichnen" ablaufen.
Tja, das war auch meine naive Vorstellung. Aber wer weiß schon was der Treiber da genau macht..
Dabei sollte es eigentlich umgekehrt sein - da die Krümmung des Ellipsoids an ober- und Unterseite geringer ist, als die der Kugel, sollte der Winkel zwischen Normalen und Y-Achse eigentlich geringer geworden sein.
Achso, jetzt verstehe ich was du mit der Trafo bewirken wolltest. Sozusagen eine Art Rück-Trafo. Die ist aber, wie du selbst sagst, nicht nötig bei einer Rotation.
...Also ich verbuche dieses eigenartige Verhalten einfach mal als undefiniertes Verhalten und mache weiter wie bisher. Als hätte ich eine Wahl, außer vielleicht mich bei Nvidia einzuschleusen...
Was genau da vor sich geht, weiß wahrscheinlich nur Nvidia und ich habe so das Gefühl, dass die darüber ungerne reden wollen würden.MfG
OpenGl-Fifi