Buchempfehlung
Windows System Programming
Windows System Programming
Das Kompendium liefert viele interessante Informationen zur Windows-Programmierung auf Englisch. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Tutorial

OpenGL und FreeBASIC - eine kleine Einführung - Teil 4 - Rotieren

von MitgliedEastler_dartSeite 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:
OpenGL_tut_laufen_von_oben
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.

 

Gehe zu Seite Gehe zu Seite  1  2  3  4  
Zusätzliche Informationen und Funktionen
  • Das Tutorial wurde am 17.08.2008 von MitgliedEastler_dart angelegt.
  • Die aktuellste Version wurde am 22.07.2012 von MitgliedAffemitwaffel gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen