Tutorial
OpenGL und FreeBASIC - eine kleine Einführung - Teil 4 - Rotieren
von Eastler_dart | Seite 3 von 4 |
und nun die Kamera schwenken/rotieren
Ja, Sie ahnen es bestimmt schon, die Vorkapitel zum Rotieren waren recht umfangreich, das Drehen der Kamera ist hinterher dann nur noch ein Klacks.
Beim Beispiel mit den zwei Pyramiden hatten wir ja gesehen, ein im Listing gesetzter Drehbefehl wirkt sich auf alle nachfolgenden Positionierungsbefehle aus, wenn man nichts dagegen unternimmt.
Und auch, wie beim verschieben der Kamera, ist ja die Vorgehensweise wieder so, daß wir unsere gesamte 3D-Welt drehen und nicht die (virtuelle) Kamera.
Also brauchen wir nur ganz am Anfang der Schleife zu rotieren, alle Anzeigeobjekte rotieren dann mit, das sieht dann aus, als würde sich die Kamera drehen.
Ran ans Werk. Analog zum Bisherigen, hängen wir die seitlichen Drehbewegungen an Tastatureingaben. Am Besten eignen sich dazu die Tastenkombinationen CTRL+CrsrRechts/links bzw. Strg+CrsrRechts/Links bei deutscher Tastaturbeschriftung.
Diese Tastenabfrage machen wir wieder über Variablen mit aussagekräftigen Namen, welche wir zuerst dimmen und mit Startwerten belegen:
'-------------------------
'DIMs
'-------------------------
.
DIM SHARED AS STRING Tlinks, Trechts, Tvor, Tzurueck, TCtrlVor, TCtrlZurueck
DIM SHARED AS STRING TCtrlLinks, TCtrlRechts :'<----------Diese Variablen zusätzlich dimmen
DIM AS SINGLE WeltDrehX, WeltDrehY, WeltDrehZ :'<----------Diese Variablen zusätzlich dimmen
.
TCtrlZurueck = CHR(255) & CHR(145) :'steht ja noch drin
TCtrlLinks = CHR(255) & CHR(115) :'<--------CURSOR NACH LINKS-Variable mit Wert belegen
TCtrlRechts = CHR(255) & CHR(116) :'<--------CURSOR NACH RECHTS-Variable mit Wert belegen
Nachdem nun die Variablen vorhanden und mit den Vergleichswerten gefüllt sind, und auch Variablen für die Speicherung der Drehwerte angelegt sind, müssen wir nun in der Tastaturabfrage die Drehwerte ändern lassen:
CASE TCtrlVor
ZRichtg = ZRichtg + 0.01 :'<----- steht ja noch drin
CASE TCtrlLinks
WeltDrehY = WeltDrehY - 1
CASE TCtrlRechts
WeltDrehY = WeltDrehY + 1
Und nun den Rotationsbefehl in der Hauptschleife noch vor den Objektanzeigebefehle setzen, am Besten gleich vor dem Verschiebebefehl der Kamera, damit um die Achse der (virtuellen)Kamera gedreht wird. Würden wir z.B. die Rotation NACH dem Verschieben ausführen, würde sich die Welt um deren Mittelachse drehen, das wäre dann für uns falsch:
IF ZRichtg < -10 THEN ZRichtg = -10 :'steht ja schon drin
glRotatef WeltDrehY, 0, 1, 0 :'<---- Hier den Rotationsbefehl der Kamera einfügen, um Y ist zu drehen
glTranslatef XRichtg, YRichtg, ZRichtg :'steht ja schon drin
Wenn wir dieses Listing dann kompilieren und starten, sieht das Ganze erst mal super aus.
Nach wie vor, per CTRL+CursorRunter rückwärts und per CTRL+CursorHoch vorwärts laufen, mit Cursor rechts nach rechts und mit Cursor links nach links laufen.
Mit Curosr Hoch/Runter ändern wir "unsere Größe/die Kamerahöhe" und jetzt neu dazu:
Mit Ctrl+Cursor-Links drehen wir uns nach links,
mit Ctrl+Cursor-Rechts drehen wir uns nach rechts.
Aber mit einem tiefergehenden Test merken wir, es stimmt doch noch nicht alles:
Drehen Sie sich mal mit Ctrl+Cursor links, bis Sie so ca 90 Grad nach links in die 3D-Welt blicken.
Und jetzt mit Ctrl+CursorHoch vorwärts laufen.
Merken Sie es? Die Kamera wandert nicht in Blickrichtung vorwärts, sondern nach wie vor auf der Y-Achse nach hinten.
Das ist mit unserer gedrehten Blickrichtung eigentlich ein NachRechtsLaufen.
Aha. Überlegen. Die Drehbewegung der Kamera mit glRotate am Anfang der Schleife mußten wir vor dem Verschiebebefehl glTranslate setzen, damit die Rotation auch wirklich um die senkrechte Achse der (virtuellen) Kamera erfolgt.
Das läßt sich nicht ändern, muß so sein. Aber diese Befehlsreihenfolge bewirkt als Nebenefekt, daß dieser nachfolgende Verschiebebefehl stur und steif sich immer nach unserem angezeigten Koordinatensystem richtet, und nicht nach der Drehrichtung unserer (virtuellen) Kamera.
Und damit ist unsere "Vorwärtsprogrammierung" per Änderung der Postion auf der Z-Achse dazu verdonnert, nach der eigentlichen Z-Achse der 3D-Welt zu verschieben.
Nochmal, wir wollten das ja eigentlich so. Bei den Pyramiden läufts ja richtig, die Zweite soll um -2 Einheiten auf der X-Achse verschoben erstellt werden, und das passiert ja auch genau so.
Würden wir jetzt an der Befehlsreihenfolge rumschrauben, wer weiß, vielleicht würde unsere Kamera-Vorwärtsbewegung dann in Sichtrichtung erfolgen, jedoch würde unsere zweite Pyramide nicht da erstellt werden, wo wir das wollen.
Noch ein Stück weiter gedacht, werden wir später bestimmt nicht nur diese Pyramiden, sondern noch etliche weitere Objekte in unsere 3D-Welt erstellen wolllen. Und, solange wir jetzt an den Rotate- und Translate-Befehlen der Kamera am Anfang der Schleife nichts ändern, werden diese weiteren Objekte auch dort erstellt werden, wo wir das wollen.
Also: Die Kamera ist das Ausnahmeobjekt, nicht die Pyramide!
Somit müssen wir für die Kamera einen gesonderten Bewegungsablauf erstellen.
und die Kamera nach Sichtrichtung bewegen
Also gehen wirs an:
Schauen wir uns mal die Situation von oben gesehen an:
In dieser Übersicht nehmen wir an, unsere Kamera steht auf Position 0,0,0 (gelber Punkt).
Die Drehrichtung wäre grad zufällig auf die grüne Linie eingestellt. Als Weite soll eine Koordinateneinheit nach vorne gelaufen werden.
In der Skizze ist klar zu sehen, die Zielposition (der weiße Punkt am Ende der grünen Linie) muß mit einem Wert auf der X-Achse (rot, in Skizze waagerecht) und einem Wert auf der Z-Achse (blau, senkrecht) angegeben werden. Der Wert ist kleiner als 1 (grüne gestrichelte Linien) und nicht genau 1 (rote gestrichelte Linien).
Sieht man die Zielpunkte (alle weißen Punkte) bei unterschiedlichen Drehgraden der Kamera, liegen diese auf einem Kreis um die Kamera (wer hätte das gedacht ;-))
Die geübten Mathematiker sehen hier gleich, daß mit Sinus und Cosinus angegriffen werden muß. Warum und wieso möcht ich hier nicht erklären, wer es noch nicht weiß, der wird es wohl eh nicht wissen wollen. Das Einzige was hier zählt ist, wie errechne ich diese Positionen, und das geht wie folgt:
Für die weißen Punkte errechnet sich der Wert für die X-Achsenangabe:
PosWert = 1 x Cosinus von Drehgrad
und für die Y-Achsenangabe:
PosWert = 1 x Sinus von Drehgrad .
Wenn wir diese Formeln nun nach FreeBasic übertragen möchten, müssen wir aber folgendes beachten:
Für OpenGL haben wir als Drehrichtung Winkelgrade (1-360) anzugeben, die Sinus/Cosinus-Funktionen von FreeBasic erwarten als Parameter aber Deg-Grade und nicht Winkelgrade!
Das bedeutet, wir müssen den vorhandenen Winkelgrad der Kameradrehung in DEG-Grade umrechnen, und zwar nach folgender Formel:
DEG = WinkelGrad X PI : 180
Das alles zusammengenommen heißt für uns, in der Tastenabfrage für 1 Schritt vorwärts dürfen wir nicht mehr einfach zur Z-Achse dazuzählen, da wir uns ja nun drehen können. Sondern wir müssen zur gerade aktuellen Position den X-Positionswert um
COS(WeltDrehY * Pi / 180)*Schrittweite verändern,
und den Z-Positionswert um
SIN(WeltDrehY * Pi / 180)*Schrittweite verändern.
Jedoch, frei nach Murphy, so einfach ist das dann doch nicht ganz, denn es gibt noch einen kleinen Unterschied:
beim FreeBasic-Sin() und Cos()Befehl liegt die Ursprungsposition für 0-Grad nach rechts, entlang der positiven X-Achse sehend, in unserer Kleinen 3D-Welt liegt die Richtung für 0-Grad entlang der negativen Y-Achse sehend.
Also obige Formeln noch wie folgt umdrehen:
nach LINKS gehen | ADDIEREN der Cos-Werte zur X-Achse und Sin-Werte zur Z-Achse | PosX=PosX+COS((WeltDrehY*Pi)/180)*Schrittweite PosY=PosY+SIN((WeltDrehY*Pi)/180)*Schrittweite |
nach RECHTS gehen | SUBTRAHIEREN der Cos-Werte zur X-Achse und Sin-Werte zur Z-Achse | PosX=PosX-COS((WeltDrehY*Pi)/180)*Schrittweite PosY=PosY-SIN((WeltDrehY*Pi)/180)*Schrittweite |
VORWÄRTS gehen | Für Sin/Cos-Berechnung 90Grad zu unseren Drehgraden dazuzählen, zu X- und Y-Werten ADDIEREN | PosX=PosX+COS(((WeltDrehY+90)*Pi)/180)*Schrittweite PosY=PosY+SIN(((WeltDrehY+90)*Pi)/180)*Schrittweite |
RÜCKWÄRTS gehen | FÜR Sin/Cos-Berechnung 90Grad von unseren Drehgraden abziehen, zu X- und Y-Werten ADDIEREN | PosX=PosX+COS(((WeltDrehY-90)*Pi)/180)*Schrittweite PosY=PosY+SIN(((WeltDrehY-90)*Pi)/180)*Schrittweite |
Jetzt stellt sich nur noch ein einziges Problem: FreeBasic kennt den Wert für Pi nicht. Also dimmen wir eine Variable Pi als Double und geben ihr den Wert für Pi:
'-------------------------
'DIMs
'-------------------------
.
.
.
DIM SHARED AS DOUBLE Pi
Pi = 3.14159265358979323846
'-------------------------
Nun können wir in der Tastaturabfrage in den
Case-Zeilen für Vorwärts/Rückwärts/NachLinks/NachRechts
die bisherigen Einträge mit den obigen Formeln ersetzen:
'---------------------------
'ProgrammSchleife
'---------------------------
'JE NACH TASTENDRUCK DEN ENTSPRECHENDEN POSITIONSWERT VERÄNDERN
SELECT CASE Tastendruck
CASE Trechts :'Falls die Taste "Cursor nach rechts" gedrückt wurde
XRichtg = XRichtg - COS((WeltDrehY * Pi) / 180) * 0.01 :' Den X-Pos-Wert anpassen
ZRichtg = ZRichtg - SIN((WeltDrehY * Pi) / 180) * 0.01 :' Den Y-Pos-Wert anpassen
CASE Tlinks :'Falls die Taste "Cursor nach links" gedrückt wurde
XRichtg = XRichtg + COS((WeltDrehY * Pi) / 180) * 0.01 :' Den X-Pos-Wert anpassen
ZRichtg = ZRichtg + SIN((WeltDrehY * Pi) / 180) * 0.01 :' Den Y-Pos-Wert anpassen
CASE Tzurueck :'Falls die Taste "Cursor runter bzw. zurück" gedrückt wurde
YRichtg = YRichtg + 0.01 :'HOCH und Runter bleibt unberührt von der Y-Drehung
CASE Tvor :'Falls die Taste "Cursor hoch bzw vor" gedrückt wurde
YRichtg = YRichtg - 0.01 :'HOCH und Runter bleibt unberührt von der Y-Drehung
CASE TCtrlZurueck
XRichtg = XRichtg + COS((WeltDrehY-90) * Pi / 180) * 0.01 :' Den X-Pos-Wert anpassen
ZRichtg = ZRichtg + SIN((WeltDrehY-90) * Pi / 180) * 0.01 :' Den Y-Pos-Wert anpassen
CASE TCtrlVor
XRichtg = XRichtg + COS((WeltDrehY+90) * Pi / 180) * 0.01 :' Den X-Pos-Wert anpassen
ZRichtg = ZRichtg + SIN((WeltDrehY+90) * Pi / 180) * 0.01 :' Den Y-Pos-Wert anpassen
CASE TCtrlLinks
.
.
.
Es wächst, und gedeiht. :-)
Eine kleine 3D-Welt ist entstanden, mit einem Koordinatensystem, einem Boden und Objekte, wir wandern in unserer kleinen Welt umher.
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|
|