Buchempfehlung
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
"Der" Petzold, das über 1000 Seiten starke Standardwerk zum Win32-API - besonders nützlich u. a. bei der GUI-Programmierung in FreeBASIC! [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 2 von 4

Na gut, dann lassen wir die Pyramide mal rotieren:

die Pyramiede drehen

Der Befehl, um Drehbewegungen zu bewirken, heißt bei OpenGL glRotate.
Der Einfachheit halber, hängen wir ein f wie floating dran, damit erwartet glRotate Kommazahlen als Parameter, auch wenn wir vorerst mit ganzen (Integer) Gradwerten arbeiten werden.
Als Parameter sucht glRotate 4 Werte wie folgt:

ParaNrBedeutung
1Gradzahl
2um X drehen?
3um Y drehen?
4um Z drehen?

Wenn wir z.B. unser Objekt um 45 Grad um die Y-Achse drehen wollten, dann müßten wir schreiben: glRotatef 45, 0, 1, 0.
Also erst den Befehl, glRotatef dann die Gradzahl 45 danach angeben, ob um die X-Achse gedreht wird (0=nein 1=ja) 0 danach angeben, ob um die Y-Achse gedreht wird (0=nein 1=ja) 1 zuletzt noch, ob um die Z-Achse gedreht wird (0=nein 1=ja) 0.

Dabei kann man auch um zwei oder alle drei Achsen gleichzeitig drehen lassen:
glRotatef 36, 1, 1, 1 würde alles, was nach dem Befehl kommt,
um 36 Grad um die X-Achse, um 36 Grad um die Y-Achse und um 36 Grad um die Z-Achse drehen.
Sie merken, wenn Sie in mehrere Richtungen gleichzeitig drehen wollen, können Sie nur eine Gradzahl für die Drehungen angeben, glRotate ließt ja nur vier Parameter.
Wollen Sie z.B. 45 Grad um Z-Achse und 10 Grad um X-Achse drehen, dann müßten Sie folgenden Zweizeiler programmieren:
glRotatef 45, 0, 0, 1
glRotatef 10, 1, 0, 0

Probieren wirs doch einfach mal aus.
Wir nehmen das Beispielprogramm von vorhin mit der Pyramide, und setzen nur noch einen glRotatef-Befehl rein:

      CASE "BESCHREIBUNGSLISTE"
         glRotatef 45, 0, 1, 0
         'die OpenGL-Beschreibungsliste zum Anzeigen der Pyramide erstellen

Also in die SUB Pyramide, im Select-Case-Fall "BESCHREIBUNGSLISTE" gleich als Erstes den Rotierbefehl rein, kompilieren und starten.

Hier zwei Bilder, das Erste noch ohne Rotate-Befehl, das Zweite mit der 45Grad-Rotation um die Y-Achse:

OpenGL_Tut_Pyramide_0grad
Vergrößern
OpenGL_Tut_Pyramide_0grad

OpenGL_Tut_Pyramide_45grad
Vergrößern
OpenGL_Tut_Pyramide_45grad

Sie sehen die Wirkung? Die Pyramide hat eine Ecke der Grundfläche zur Kamera gedreht.

Aber wie beim Verschieben auch hier, ein Stillleben. Die Pyramide wird bei jeder Bilderstellung(Schleifendurchlauf) um 45 Grad um Y gedreht, kommt also bei jedem erstellten Bild(Schleifendurchlauf) immer wieder auf ein und dieselbe Ausrichtung, somit auf jedem Bild immer gleich.

kontrolliertes Rotieren

Um jetzt hier Bewegung reinzukriegen, machen wir das auf die selbe Art, wie beim Verschieben. Wir "füttern" glRotate mit Variablen anstelle von festen Werten. Und den Inhalt dieser Variablen ändern wir in Abhängigkeit von der Tastatur. Und gleich noch für alle drei Achsen:

Also brauchen wir erst mal 3 Variablen, in denen die jeweilige Gradzahl für die Drehung gespeichert werden kann. Diese Variablen nennen wir sinnigerweise: PyraXDrehw, PyraYDrehw, PyraZDrehw.
Auch wenn uns hier Integerwerte(Ganzzahlen ohne Kommastellen) reichen würden, der Einfachheit halber nehmen wir wieder SINGLE-Variablen, welche auch Kommastellen speichern können. Wir dimmen also im Hauptprogramm diese drei Variablen:

'-------------------------
'DIMs
'-------------------------
.
.
.
TCtrlZurueck = CHR(255) & CHR(145)  :'Ctrl oder STRG zusammen mit CursorRunter
DIM AS SINGLE XRichtg, YRichtg, ZRichtg
DIM AS SINGLE PyraXDrehw, PyraYDrehw, PyraZDrehw :'<------------------------ für Pyramide per Tasten drehen
'-------------------------

Einen Speicherplatz für die drei verschiedenen Winkelwerte für das Rotieren haben wir jetzt. Nun müssen wir diese Variablen mit Werten belegen, wie gesagt, in Abhängigkeit von der Tastatur.

Schlage vor, wir nehmen einfach die Buchstaben X, Y, und Z. Und dabei unterscheiden wir noch, ob diese Buchstaben als kleine oder als große Buchstaben gedrückt wurden. Je nachdem erhöhen oder vermindern wir den Variableninhalt.

Also brauchen wir neue CASE-Fälle in unserer Tastaturauswertung per SELECT CASE im Hauptteil:

   '---------------------------
   'ProgrammSchleife
   '---------------------------

   'JE NACH TASTENDRUCK DEN ENTSPRECHENDEN POSITIONSWERT VERÄNDERN
   SELECT CASE Tastendruck
      CASE Trechts                :'Falls die Taste "Cursor nach rechts" gedrückt wurde
      .
      .
      .
      CASE "x"
         PyraXDrehw=PyraXDrehw+1
      CASE "x"
         PyraXDrehw=PyraXDrehw-1
      CASE "y"
         PyraYDrehw=PyraYDrehw+1
      CASE "y"
         PyraYDrehw=PyraYDrehw-1
      CASE "z"
         PyraZDrehw=PyraZDrehw+1
      CASE "z"
         PyraZDrehw=PyraZDrehw-1

Tja, da fällt mir ein, es wird ja jetzt recht chaotisch werden, wenn man mal die Pyramide z.B. um 128 Grad über X gedreht hat, und dann Z oder Y drückt.
Damit man auch abfragen kann, um wieviele Grad denn nun um welche Achse grad gedreht wird, sollte man das auch anzeigen.

Da wir noch nicht soweit sind, mit OpenGL Texte anzuzeigen und gleichzeitig wissen, mit FreeBasic-Print gehts in einem OpenGL-Fenster auch nicht, weichen wir auf das Console-Fenster aus.
Falls Sie routinierter FreeBasicler sind, könnte es sein, daß Sie Basic-Listings mit dem Parameter -s gui compilieren. Das ist schön und gut, stört uns hier aber. Bitte compilieren Sie hier ohne diesen Parameter, sodaß beim Programmstart dann zwei Fenster auf sind, das Console-Fenster und auch das Open-GL-Fenster.

Also, die Gradzahlen der Drehung zu jeder Achse auf dem Konsolefenster ausgeben läuft über den BefehlsreferenzeintragOpen-Befehl - mit Open die Konsole für Ausgabe öffnen, mit BefehlsreferenzeintragPrint # reinschreiben und danach schließen. Das ganze aber nicht durchweg, sonst scrollt das Fenster nur noch und OpenGL schläft ein, sondern nur dann, wenn der Anwender das will.

Jedoch wird das Ausgeben von SINGLE-Variablen von FreeBasic gern mal mit Exponential oder sonstigen Schreibweisen durchgeführt, deshalb würde ich die Ausgabe gerne mit dem Format-Befehl in eine klare Ausgabeform umsetzen. Dafür muß aber eine zusätzliche Datei, die vbcompat.bi, includet werden, weil dort erst der Formatbefehl drin steht:

'---------------------------
'Includes
'-------------------------
#include "fbgfx.bi"
#include once "GL/gl.bi"
#include once "GL/glu.bi"
#include once "vbcompat.bi" '<--------------um Zahlen per "format()" formatieren zu können

Für den Open-Befehl brauchen wir noch eine Dateinummer, welche wir in der Integer-Variablen ConNrfesthalten müssen.
Also diese erst dimmen:

'---------------------------
'DIMs
'-------------------------
.
.
DIM AS INTEGER ConNr                :' Dateinummerspeicher beim Consolefenster öffnen
'-------------------------

Nun hängen wir die Ausgabe der Winkelwerte in die Tastaturabfrageroutine, und zwar, wenn der Anwender "I" oder "i" drückt (für Info als Eselsbrücke). Da wir nun Werte anzeigen, nehm ich gleich noch die Positionswerte der Kamera mit dazu, diese Infos sind auch manchmal interessant:

   '---------------------------
   'ProgrammSchleife
   '---------------------------
   .
   .
   SELECT CASE Tastendruck
   .
   .
      CASE "Z"
         PyraZDrehw=PyraZDrehw-1
      CASE "i", "i"                       :'<------------------------
         ConNr = FREEFILE                 :'nächste freie Dateinummer für öffnen von FreeBasic holen und in ConNr merken
         open "con" FOR OUTPUT AS #ConNr  :'und nun die Konsole als Datei unter Nr ConNr öffnen
            PRINT #ConNr, "PyraXDrehw:" & format(PyraXDrehw,"0.00") & "  PyraYDrehw:" & format(PyraYDrehw,"0.00") & "  PyraZDrehw:" & format(PyraZDrehw,"0.00")
            PRINT #ConNr, "XRichtg:" & format(XRichtg,"0.00") & "  YRichtg:" & format(YRichtg,"0.00") & "  ZRichtg:" & format(ZRichtg,"0.00")
         CLOSE #ConNr

Nachdem nun die Variablen vorhanden sind, per Tastendruck mit Werten gefüllt werden und auch angezeigt werden können, müssen wir nur noch der Pyramidenroutine sagen, "dreh die Pyramide". Das mach ich nun mal über den Sub-Aufruf, damit Sie diese Möglichkeit auch mal sehen, also in der Hauptschleife, beim Aufruf der Pyramidensub die Drehwerte mit übergeben:

   '---------------------------
   '---------------------------
   'ProgrammSchleife
   '---------------------------
   'JE NACH TASTENDRUCK DEN ENTSPRECHENDEN POSITIONSWERT VERÄNDERN
   .
   .
    Schachbrettboden("BeschreibungsListeBoden", "", 0, 0, 0)
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'<-------------------------------
    flip                                               :'liebes OpenGL, zeig alles, was in der Schleife für dich vornedran steht, auf Monitor an

Nun stehen die Drehwerte in der Sub Pyramide zur Verfügung, die wie folgt zu einer Rotation zusammengebastelt werden.
Da wir mit drei verschiedenen Drehwinkelwerten arbeiten, müssen wir die Rotation in drei Befehlszeilen aufteilen. Die erste Zeile nimmt Para1(übergebner Wert in PyraXDrehw) und dreht um die X-Achse, die Zweite nimmt Para2(übergebener Wert in PyraYDrehw) und dreht um Y-Achse, die dritte Zeile macht das gleiche für die Z-Achse:

SUB Pyramide(was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
.
.
   SELECT CASE UCASE(was)
.
.
      CASE "BESCHREIBUNGSLISTE"
         'die OpenGL-Beschreibungsliste zum Anzeigen der Pyramide erstellen
         glrotatef Para1, 1, 0, 0    :'<----------- um X-Achse drehen
         glrotatef Para2, 0, 1, 0    :'<----------- um Y-Achse drehen
         glrotatef Para3, 0, 0, 1    :'<----------- um Z-Achse drehen
         glBegin GL_QUADS
.
.

Wenn Sie das jetzt kompilieren und ausführen, können Sie mit den Cursortasten wie gehabt die Kamera steuern: links, rechts, hoch und runter, sowie mit Ctrl+CrsrHoch bzw. Ctrl+CrsrRunter die Kamera auf der Z-Achse vor und zurück bewegen.
Zusätztlich jetzt:

zwei Pyramiden und beide rotieren

Was aber nun, wenn wir zwei Pyramiden erstellen wollen? Probieren wirs einfach mal, in der Hauptschleife, nach dem Aufruf der PyramidenSUB für die erste Pyramide einfach einen Verschiebe-Befehl anfügen und danach nochmal die PyramidenSUB aufrufen:

    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'steht ja schon drin
    glTranslatef -2, 0, 0    :' Anzeigeposition auf neue Werte einstellen    :'<-----hier der Verschiebebefehl
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'<-----und eine zweite Pyramide

    flip                                               :'liebes OpenGL, zeig alles, was in der Schleife für dich vornedran steht, auf Monitor an

Das Programm mit diesen Änderungen kompiliert und gestartet, mit den Cursortasten die Kamera auf eine geeignete Position gesetzt zeigt sich beim "y"-Drücken folgende Animation:
planetpyramiden.gif
Hier ist zu erkennen, daß viel mehr rotiert wird, als wir dies wollten :-O

Was passiert:
Die erste Pyramide, welche zentriert im Koordinatensystem steht, läuft richtig, sie dreht sich um Ihre innere Achse.

Aber unsere Verschiebung vor der zweiten Pyramide wird relativ zur Drehrichtung der ersten Pyramide verschoben, und da bei jedem Tastendruck(y) diese erste Pyramide um ein weiteres Grad gedreht wird, wird die Verschiebung für die zweite Pyramide um eben dieses weitere Grad in der Richtung geändert. Daraus ergibt sich dann, daß die zweite Pyramide um die erste rotiert, so wie der Mond um die Erde.
Gleichzeitig senden wir für den Aufbau der zweiten Pyramide nochmal die gleichen Gradzahlen für eine Rotation der zweiten Pyramide, diese Rotation erfolgt dann richtiger Weise um die innere senkrechte Achse dieser zweiten Pyramide.
Damit Rotiert diese zusätzlich noch um sich selbst.

HM. Überlegen. Eine Verschiebung nach einem Rotate richtet sich also nach der Gradzahl des Rotate-Befehls.

Richtig. Der Rotationswert wird ebenfalls auf dem Stack gespeichert! Also dort, wo wir im vorigen Kapitel OpenGL Zettel untergeschoben hatten. Auf diesen Zetteln steht also nicht nur die grad aktuelle Verschiebeposition, sondern auch der Rotationswert der drei Achsen.

Ja, dann, äh, klar, auch bei einer Rotation müssen wir vorher einen zusätzlichen Zettel unterschieben(push) dann rotieren, das Objekt rotiert anzeigen, und hinterher per pop den zusätzlichen, nun veränderten Zettel wegschmeißen. Nur so richtet sich alles, was danach kommt, nach der von uns gewollten Position.

Also, bevor wir die SUB für die erste Pyramide aufrufen, pushen wir einen zusätzlichen Zettel auf den Stapel. Nachdem die erste Pyramide angezeigt ist, popen wir diesen zusätzlichen Zettel vom Stapel (in Mülleimer), die zweite Pyramide wird dann vom Nullpunkt unserer 3D-Welt aus verschoben, genau so, wie wir das wollten.

Wir ändern also in der Hauptschleife bei den Pyramidenaufrufen:

    Schachbrettboden("BeschreibungsListeBoden", "", 0, 0, 0)
    glPushMatrix :'<--------zusätzlicher Zettel unterschieben
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'<-----die erste Pyramide
    glPopMatrix :'<---------zusätzlichen Zettel wegschmeißen
    glTranslatef -2, 0, 0    :' Anzeigeposition auf neue Werte einstellen    :'<-----hier der Verschiebebefehl
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'<-----und eine zweite Pyramide
    flip

So, jetzt paßts, die Pyramiden aus einer einzige SUB stehen wie geplant nebeneinander und drehen sich (nur) um die eigene, innere, senkrechte Mittelachse. Schön.

Das einzigste, was uns zu denken gibt, ist wenn man z.B.
- mit Z die beiden Pyramiden zur Seite neigt, um danach
- mit Y wieder um die senkr. Mittelachse der Pyramiden
drehen zu wollen, das läuft dann anderst!
Die drehen um die viertuelle, wirkliche senkrechte Achse, nicht um die durch die Z-Rotation gekippte eigentliche Achse der Pyramiden!
Das läßt sich für diesen speziellen Fall beheben, indem man die Reihenfolge der drei Rotationsbefehle in der Pyramidensub umkehrt, also zuerst um die Z-Achse, dann um Y und danach um X-Achse rotieren. Damit würden in dem erwähnten Beispiel die Pyramiden zur Seite gekippt werden und danach trotzdem um die eigene Mittelachse rotieren.
Wenn man nun aber in dieser Konstellation mit der umgekehrten Rotationsreihenfolge zuerst um die X-Achse dreht, um danach um Y zu drehen, ergibt sich das Problem dann wieder, was in der ursprünglichen Programmierung mit zuerst X, dann Y und zuletzt Z-Drehung nicht vorhanden war.

Wir merken uns also, man kann nicht wahllos einfach alle drei Richtungen für die Rotation angeben, man muß dabei die jeweils notwendige Reihenfolge der Drehbefehle beachten!

Zur Übersichtlichkeit das gesamte Listing hier nochmal:

'REM Tutorial 4 - OpenGL-Tutorial von Eastler
'-------------------------
'DIMs
'-------------------------
DIM SHARED AS STRING Tastendruck
DIM SHARED AS STRING Tlinks, Trechts, Tvor, Tzurueck, TCtrlVor, TCtrlZurueck
Tlinks       = CHR(255) & CHR( 75)  :' beim Drücken der Taste CursorLinks gibt die Tastatur CHR(255) & CHR( 75) zurück
Trechts      = CHR(255) & CHR( 77)  :' CursorRechts
Tvor         = CHR(255) & CHR( 72)  :' CursorHoch
Tzurueck     = CHR(255) & CHR( 80)  :' CursorRunter
TCtrlVor     = CHR(255) & CHR(141)  :'Ctrl oder STRG zusammen mit CursorHoch
TCtrlZurueck = CHR(255) & CHR(145)  :'Ctrl oder STRG zusammen mit CursorRunter
DIM AS SINGLE XRichtg, YRichtg, ZRichtg
DIM AS SINGLE PyraXDrehw, PyraYDrehw, PyraZDrehw :'<------------------------ für Pyramide per Tasten drehen
DIM AS INTEGER ConNr                :' Dateinummerspeicher beim Consolefenster öffnen
'-------------------------
'Includes
'-------------------------
#include "fbgfx.bi"
#include once "GL/gl.bi"
#include once "GL/glu.bi"
#include once "vbcompat.bi" '<--------------um Zahlen per "format()" formatieren zu können

'-------------------------
'Declarationen
'-------------------------
'-------------------------
'Declarationen
'-------------------------
DECLARE SUB Koordinatensystem(was AS STRING, TxtPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
DECLARE SUB Objekt1()
DECLARE SUB BewegtePunkte()
DECLARE SUB Schachbrettboden(was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
DECLARE SUB Pyramide (was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)

'-------------------------
' das Fenster öffnen
'-------------------------
screen 19, 16, , 2

'-------------------------
' Open-GL Init
'-------------------------
glViewport 0, 0, 800, 600                      ' den Current Viewport auf eine Ausgangsposition setzen
glMatrixMode GL_PROJECTION                     ' Den Matrix-Modus Projection wählen
glLoadIdentity                                 ' Diesen Modus auf Anfangswerte setzen
gluPerspective 45.0, 800.0/600.0, 0.1, 100.0   ' Grundeinstellungen des Anezeigefensters festlegen
glMatrixMode GL_MODELVIEW                      ' Auf den Matrix-Modus Modelview schalten
glLoadIdentity                                 ' und auch diesen auf Anfangswerte setzen
glClearColor 0.5, 0.5, 0.50, 0.0               ' Setze Farbe für löschen auf Mittelgrau
glClearDepth 1.0                               ' Depth-Buffer Löschen erlauben
glEnable GL_DEPTH_TEST                         ' den Tiefentest GL_DEPTH_TEST einschalten
glClear GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT  'Tiefen- und Farbpufferbits löschen
'---------------------------
'HAUPTTEIL
'---------------------------
Schachbrettboden("SetzKantenLaenge", "", 0.5,  0,    0)
Schachbrettboden("SetzQuadsZahl",    "", 24,   24,   0)     :'6 Einheiten +und- = 12Einheiten Koordiantensystem, bei 0.5 Quadgröße 24 Stück
Schachbrettboden("SetzFarbe1",       "", 0,    0,    0.5)   :'erste Farbe dunkleres blau
Schachbrettboden("SetzFarbe2",       "", 0.25, 0.25, 0.25)  :'erste Farbe dunkles grau
Schachbrettboden("SetzStartPos",     "", -6,   -6,   -1)     :'ganz vorne ganz links beginnen, Boden auf Hoehe(3.Para)-1 verlegen(Y)

Pyramide("SetzLaengen" , "", 1, 1,  1)
Pyramide("SetzFarbe1"  , "", 1, 0, 0)
Pyramide("SetzFarbe2"  , "", 0, 1, 0)
Pyramide("SetzFarbe3"  , "", 0, 0, 1)
Pyramide("SetzFarbe4"  , "", 1, 1, 0)
Pyramide("SetzFarbe5"  , "", 1, 0, 1)

DO UNTIL Tastendruck = CHR(27)                         :'die Schleife solange immer wiederholen, bis in der Variablen Tastendruck die Esc-Taste (chr(27) steht
   Tastendruck = INKEY                                 :'Jeder Tastendruck wird sofort in die Variable Tastendruck gespeichert
   glClear GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT  :'bisherig erstellte Objekte löschen, unsere 3D-Welt wieder von Neuem an erstellen
   glPushMatrix                                        :'aktuelle Position sichern (2.Zettel mit gleicher Pos auf PositionsSTACK)
   '---------------------------
   '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 - 0.04 :'um -0.01 in X-Richtung = 0.01 nach links
      CASE Tlinks                 :'Falls die Taste "Cursor nach links" gedrückt wurde
         XRichtg = XRichtg + 0.04 :'um +0.01 in X-Richtung = 0.01 nach links
      CASE Tzurueck               :'Falls die Taste "Cursor runter bzw. zurück" gedrückt wurde
         YRichtg = YRichtg + 0.04 :'um +0.01 in Y-Richtung = 0.01 nach oben
      CASE Tvor                   :'Falls die Taste "Cursor hoch bzw vor" gedrückt wurde
         YRichtg = YRichtg - 0.04 :'um -0.01 in Y-Richtung = 0.01 nach unten
      CASE TCtrlZurueck
         ZRichtg = ZRichtg - 0.04 :'um -0.01 in Y-Richtung = 0.01 nach unten
      CASE TCtrlVor
         ZRichtg = ZRichtg + 0.04 :'um -0.01 in Y-Richtung = 0.01 nach unten
      CASE "x"
         PyraXDrehw=PyraXDrehw+1
      CASE "x"
         PyraXDrehw=PyraXDrehw-1
      CASE "y"
         PyraYDrehw=PyraYDrehw+12
      CASE "y"
         PyraYDrehw=PyraYDrehw-12
      CASE "z"
         PyraZDrehw=PyraZDrehw+1
      CASE "z"
         PyraZDrehw=PyraZDrehw-1
      CASE "i", "i"                       :'<------------------------
         ConNr = FREEFILE                 :'nächste freie Dateinummer für öffnen von FreeBasic holen und in ConNr merken
         open "con" FOR OUTPUT AS #ConNr  :'und nun die Konsole als Datei unter Nr ConNr öffnen
            PRINT #ConNr, "PyraXDrehw:" & format(PyraXDrehw,"0.00") & "  PyraYDrehw:" & format(PyraYDrehw,"0.00") & "  PyraZDrehw:" & format(PyraZDrehw,"0.00")
            PRINT #ConNr, "XRichtg:" & format(XRichtg,"0.00") & "  YRichtg:" & format(YRichtg,"0.00") & "  ZRichtg:" & format(ZRichtg,"0.00")
         CLOSE #ConNr
   END SELECT
   'PRÜFEN, DASS DIE POSITIONSWERTE IN ALLEN DREI RICHTUNGEN ZWISCHEN -3 und +3 BLEIBEN
   IF XRichtg >  6 THEN XRichtg =  6           :'falls zu weit rechts, bei  6 festnageln
   IF XRichtg < -6 THEN XRichtg = -6           :'falls zu weit links,  bei -6 festnageln
   IF YRichtg >  6 THEN YRichtg =  6           :'falls zu weit hoch,   bei  6festnageln
   IF YRichtg < -6 THEN YRichtg = -6           :'falls zu weit runter, bei -6 festnageln
   IF ZRichtg >  5 THEN ZRichtg =  5           :'falls zu weit zurück, bei 10 festnageln
   IF ZRichtg < -10 THEN ZRichtg = -10           :'falls zu weit vor,    bei -6 festnageln
    glTranslatef XRichtg, YRichtg, ZRichtg    :' Anzeigeposition auf neue Werte einstellen

    glPointSize(5)                             :' Punktgröße auf 5 = deutlich groß
    glColor3f 1.0,0.0,0.0                      :' Anzeigefarbe auf ROT setzen
'    Objekt1()                                  :' Sub Objekt1 aufrufen, in der zwei Punkte an der grad aktuellen Pos erstellt werden
    Koordinatensystem("", "", 0, 0, 0)
    Schachbrettboden("BeschreibungsListeBoden", "", 0, 0, 0):'<-----------------------HIER WIRD UNSER BODEN AUFGERUFEN
    glPushMatrix :'<----------------------------------
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'<-----die erste Pyramide
    glPopMatrix :'<----------------------------------
    glTranslatef -2, 0, 0    :' Anzeigeposition auf neue Werte einstellen    :'<-----hier der Verschiebebefehl
    Pyramide("BeschreibungsListe"  , "", PyraXDrehw, PyraYDrehw, PyraZDrehw) :'<-----und eine zweite Pyramide

    flip                                               :'liebes OpenGL, zeig alles, was in der Schleife für dich vornedran steht, auf Monitor an
   '---------------------------
   'Ende der Schleife
   '---------------------------
   glPopMatrix                                         :' Aufgabe erledigt, den zweiten Zettel mit der geänderten Pos wegschmeißen, dann ist Alte Pos wieder aktuelle Pos
LOOP

END

'-------------------------
SUB BewegtePunkte()
   STATIC AS SINGLE Seite, Hoehe, Tiefe  'Static, damit die Vars beim nächsten Aufruf der Schleife immer noch den Wert haben
   Seite=Seite + 0.01
   IF Seite > 3 THEN Seite = -3     :'damit halten wir den Wert von Seite zwischen -3 und +3
   glTranslatef Seite, 0, -6        :'wir Positionieren die Anzeige fest auf -6 der Z-Achse = im Kamerabereich und beweglich auf der X-Achse
   Objekt1()
END SUB
'-------------------------
SUB Objekt1()
  glBegin GL_POINTS        'Beschreibungsliste für Punkte beginnen
     glVertex3f   1,  1, 0 'einen Punkt auf 1/1/0
     glVertex3f  -1, -1, 0 'noch einen Punkt, dieser auf -1/-1/0
  glEnd                    'Ende der Beschreibungsliste (hier für Punkte)
END SUB
'--------------------------------
SUB Koordinatensystem(was AS STRING, TxtPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
   DIM AS INTEGER Zaehler
'glPushMatrix
         glBegin GL_LINES:' Ja, wir beginnen mit der Beschreibungsliste fuer Linien
         'und zwar zuerst die positiven Bereiche jeder Achse
         glColor3f 1.0, 1.0, 1.0        :' Positives Maß = weiße Teilstriche (Rot 1.0, blau 1.0, grün 1.0 = weiß)
         FOR Zaehler = 1 TO 6 :'fuer die Maßeinheitspositionen 1, 2 und 3 Striche Ziehen
            'X-ACHSE
               'senkrechter Strich (wie Y-Achse)
            glVertex3f  Zaehler+Para1,  0.2+Para2,  0.0+Para3 :' Anfangspunkt auf XAchse-Maßpunkt, 0.2 Einheiten drüber(+Y), Tiefe = 0
            glVertex3f  Zaehler+Para1, -0.2+Para2,  0.0+Para3 :' Endpunkt auf XAchse-Maßpunkt, 0.2 Einheiten drunter(-Y), Tiefe = 0
               'waagerechter Strich (wie Z-Achse)
            glVertex3f  Zaehler+Para1,  0.0+Para2,  0.2+Para3 :' Anfangspunkt auf XAchse-Maßpunkt, 0.2 Einheiten drüber(+Y), Tiefe = 0
            glVertex3f  Zaehler+Para1,  0.0+Para2, -0.2+Para3 :' Endpunkt auf XAchse-Maßpunkt, 0.2 Einheiten drunter(-Y), Tiefe = 0
            'Y-ACHSE
               'Strich wie X-Achse
            glVertex3f  0.2+Para1, Zaehler+Para2,  0.0+Para3 :' Anfangspunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach +X, Tiefe = 0
            glVertex3f -0.2+Para1, Zaehler+Para2,  0.0+Para3 :' Endpunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach -X, Tiefe = 0
               'Strich wie Z-Achse
            glVertex3f  0.0+Para1, Zaehler+Para2,  0.2+Para3 :' Anfangspunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach vorne/+Z, Seite (X) = 0
            glVertex3f  0.0+Para1, Zaehler+Para2, -0.2+Para3 :' Endpunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach hinten/-Z, Seite (X) = 0
            'Z-ACHSE
               'Strich waagerecht (X)
            glVertex3f  0.2+Para1,  0.0+Para2, Zaehler+Para3 :' Anfangspunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach rechts +X, Hoehe = 0
            glVertex3f -0.2+Para1,  0.0+Para2, Zaehler+Para3 :' Endpunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach links -X, Hoehe = 0
               'Strich senkreicht (Y)
            glVertex3f  0.0+Para1,  0.2+Para2,  Zaehler+Para3 :' Anfangspunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach oben +Y, Seite = 0
            glVertex3f  0.0+Para1, -0.2+Para2,  Zaehler+Para3 :' Endpunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach unten -Y, Seite = 0
         NEXT Zaehler
         glColor3f 0.0, 0.0, 0.0        :' Negatives Maß = schwrze Teilstriche (alles auf 0)
         FOR Zaehler = -6 TO -1 :'fuer die Maßeinheitspositionen -3, -2 und -1 Striche Ziehen
         'X-ACHSE
            'senkrechter Strich (wie Y-Achse)
            glVertex3f  Zaehler+Para1,  0.2+Para2,  0.0+Para3 :' Anfangspunkt auf XAchse-Maßpunkt, 0.2 Einheiten drüber(+Y), Tiefe = 0
            glVertex3f  Zaehler+Para1, -0.2+Para2,  0.0+Para3 :' Endpunkt auf XAchse-Maßpunkt, 0.2 Einheiten drunter(-Y), Tiefe = 0
            'waagerechter Strich (wie Z-Achse)
            glVertex3f  Zaehler+Para1,  0.0+Para2,  0.2+Para3 :' Anfangspunkt auf XAchse-Maßpunkt, 0.2 Einheiten drüber(+Y), Tiefe = 0
            glVertex3f  Zaehler+Para1,  0.0+Para2, -0.2+Para3 :' Endpunkt auf XAchse-Maßpunkt, 0.2 Einheiten drunter(-Y), Tiefe = 0
            'Y-ACHSE
               'Strich wie X-Achse
            glVertex3f  0.2+Para1, Zaehler+Para2,  0.0+Para3 :' Anfangspunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach +X, Tiefe = 0
            glVertex3f -0.2+Para1, Zaehler+Para2,  0.0+Para3 :' Endpunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach -X, Tiefe = 0
               'Strich wie Z-Achse
            glVertex3f  0.0+Para1, Zaehler+Para2,  0.2+Para3 :' Anfangspunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach vorne/+Z, Seite (X) = 0
            glVertex3f  0.0+Para1, Zaehler+Para2, -0.2+Para3 :' Endpunkt auf YAchse-Maßpunkt, 0.2 Einheiten nach hinten/-Z, Seite (X) = 0
            'Z-ACHSE
               'Strich waagerecht (X)
            glVertex3f  0.2+Para1,  0.0+Para2, Zaehler+Para3 :' Anfangspunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach rechts +X, Hoehe = 0
            glVertex3f -0.2+Para1,  0.0+Para2, Zaehler+Para3 :' Endpunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach links -X, Hoehe = 0
               'Strich senkreicht (Y)
            glVertex3f  0.0+Para1,  0.2+Para2,  Zaehler+Para3 :' Anfangspunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach oben +Y, Seite = 0
            glVertex3f  0.0+Para1, -0.2+Para2,  Zaehler+Para3 :' Endpunkt auf ZAchse-Maßpunkt, 0.2 Einheiten nach unten -Y, Seite = 0
         NEXT Zaehler
         'UND NUN DIE DREI ACHSEN SELBST:
         'X-ACHSE
         glColor3f 1.0, 0.0, 0.0        :' Xachse = rot
         glVertex3f  -6.0+Para1, 0+Para2, 0+Para3
         glVertex3f  +6.0+Para1, 0+Para2, 0+Para3
         'Y-ACHSE
         glColor3f 0.0, 1.0, 0.0        :' Yachse = grün
         glVertex3f  0+Para1, -6.0+Para2, 0+Para3
         glVertex3f  0+Para1, +6.0+Para2, 0+Para3
         'Z-ACHSE
         glColor3f 0.0, 0.0, 1.0        :' Zachse = blau
         glVertex3f  0+Para1, 0+Para2, -6.0+Para3
         glVertex3f  0+Para1, 0+Para2, +6.0+Para3
      glEnd
'glPopMatrix
END SUB
'-------------------------
SUB Schachbrettboden(was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
   STATIC AS SINGLE QuadKantenLaenge, QuadsQuer, QuadsTief
   STATIC AS SINGLE Farbe1Rot, Farbe1Gruen, Farbe1Blau
   STATIC AS SINGLE Farbe2Rot, Farbe2Gruen, Farbe2Blau
   STATIC AS SINGLE StartPosX, StartPosZ, BodenHoehe
   STATIC AS INTEGER ZaehlerX, ZaehlerZ                   :'ForNext-Zählvars, ggf. rekursiver aufruf dieser Sub, drum STATIC
   SELECT CASE UCASE(was)
      CASE "SetzKantenLaenge"
         'Aufruf hierfür in Para1 die Länge der Kanten der Quadrate
         QuadKantenLaenge = Para1
      CASE "SetzQuadsZahl"
         'Aufruf hierfür in Para1 die Anzahl von Quads quer,
         'in Para2 die Anzahl in der Tiefenrichtung
         QuadsQuer = Para1
         QuadsTief = Para2
      CASE "SetzFarbe1"
         'in Para1 Para2 Para2 die Rot Grün und Blauwerte der ersten Quadratfarbe
         Farbe1Rot   = Para1
         Farbe1Gruen = Para2
         Farbe1Blau  = Para3
      CASE "SetzFarbe2"
         'in Para1 Para2 Para2 die Rot Grün und Blauwerte der ersten Quadratfarbe
         Farbe2Rot   = Para1
         Farbe2Gruen = Para2
         Farbe2Blau  = Para3
      CASE "SetzStartPos"
         'in Para1 Para2 Para2 die X und Z Position, von wo begonnen wird,
         'die vielen Quadrate zu erstellen
         StartPosX   = Para1
         StartPosZ   = Para2
         BodenHoehe  = Para3
      CASE "BeschreibungsListeBoden"
         'Hier erstellen wir die FOR-NEXT-SCHLEIFEN,
         'welche die OpenGL-Beschreibungsliste
         'zum Anzeigen des Bodens erstellen
         glBegin GL_QUADS
            FOR ZaehlerX = 1 TO QuadsQuer     :'Laufnr des grad zu zeichnenden Quads auf der X-Achse
               FOR ZaehlerZ = 1 TO QuadsTief  :'Laufnr des grad zu zeichnenden Quads auf der Z-Achse
                  'Die Farbe festlegen
                  IF ((ZaehlerX+ZaehlerZ)\2)*2=(ZaehlerX+ZaehlerZ) THEN
                     'Wenn die Summe von ZahlerX+ZaehlerY gerade ist Farbe1 nehmen
                     glColor3f Farbe1Rot, Farbe1Gruen, Farbe1Blau
                  ELSE
                     'Wenn die Summe von ZahlerX+ZaehlerY UNgerade ist Farbe2 nehmen
                     glColor3f Farbe2Rot, Farbe2Gruen, Farbe2Blau
                  END IF
                  'Die Eckpunkte der Quadrate benennen wir in der Reihenfolge GEGEN DEN UHRZEIGERSINN, von oben draufschauend
                  glVertex3f StartPosX+(ZaehlerX-1)*QuadKantenLaenge,  BodenHoehe,  StartPosZ+(ZaehlerZ-1)*QuadKantenLaenge
                  glVertex3f StartPosX+ ZaehlerX   *QuadKantenLaenge,  BodenHoehe,  StartPosZ+(ZaehlerZ-1)*QuadKantenLaenge
                  glVertex3f StartPosX+ ZaehlerX   *QuadKantenLaenge,  BodenHoehe,  StartPosZ+ ZaehlerZ   *QuadKantenLaenge
                  glVertex3f StartPosX+(ZaehlerX-1)*QuadKantenLaenge,  BodenHoehe,  StartPosZ+ ZaehlerZ   *QuadKantenLaenge
               NEXT ZaehlerZ
            NEXT ZaehlerX
         glEnd
      CASE ELSE
         'Hier kommen alle SUB-Aufrufe an, welche als
         'was-Parameter einen Eintrag haben, der hier
         'nicht ausgewertet wurde.
         'Tippfehler vom Programmierer????
   END SELECT
END SUB
'-------------------------
SUB Pyramide(was AS STRING, StrPara AS STRING, Para1 AS SINGLE, Para2 AS SINGLE, Para3 AS SINGLE)
   'Pyramide erstellen, Grundfläche/Quadrat = auf Höhe 0, seitlich mittig auf X- und Z-Achse Positioniert
   'Grundflächengroesse = XLaenge x ZLaenge, Höhe Pyramide = ZLaenge
   STATIC AS SINGLE XLaenge, YLaenge, ZLaenge
   STATIC AS SINGLE Farbe1Rot, Farbe1Gruen, Farbe1Blau
   STATIC AS SINGLE Farbe2Rot, Farbe2Gruen, Farbe2Blau
   STATIC AS SINGLE Farbe3Rot, Farbe3Gruen, Farbe3Blau
   STATIC AS SINGLE Farbe4Rot, Farbe4Gruen, Farbe4Blau
   STATIC AS SINGLE Farbe5Rot, Farbe5Gruen, Farbe5Blau
   STATIC AS INTEGER ZaehlerX, ZaehlerZ                   :'ForNext-Zählvars, ggf. rekursiver aufruf dieser Sub, drum STATIC
   SELECT CASE UCASE(was)
      CASE "SetzLaengen"  : XLaenge   = Para1 : YLaenge     = Para2 : ZLaenge     = Para3
      CASE "SetzFarbe1"   : Farbe1Rot = Para1 : Farbe1Gruen = Para2 : Farbe1Blau  = Para3 :'ein Dreieck
      CASE "SetzFarbe2"   : Farbe2Rot = Para1 : Farbe2Gruen = Para2 : Farbe2Blau  = Para3 :'ein Dreieck
      CASE "SetzFarbe3"   : Farbe3Rot = Para1 : Farbe3Gruen = Para2 : Farbe3Blau  = Para3 :'ein Dreieck
      CASE "SetzFarbe4"   : Farbe4Rot = Para1 : Farbe4Gruen = Para2 : Farbe4Blau  = Para3 :'ein Dreieck
      CASE "SetzFarbe5"   : Farbe5Rot = Para1 : Farbe5Gruen = Para2 : Farbe5Blau  = Para3 :'der Boden/Quadrat
      CASE "BeschreibungsListe"
         glrotatef Para1, 1, 0, 0    :'<----------- um X-Achse drehen
         glrotatef Para2, 0, 1, 0    :'<----------- um Y-Achse drehen
         glrotatef Para3, 0, 0, 1    :'<----------- um Z-Achse drehen
         'die OpenGL-Beschreibungsliste zum Anzeigen der Pyramide erstellen
         glBegin GL_QUADS
            'der Boden der Pyramide als Quadrat, auf Höhe 0(Y-Achse),
            'seitliche Ausrichtungen = Quadratmitte = X-Achsenmitte und Z-Achsenmitte
            'damit Zentriert sitzt, für 1.Punkt einfach halbe Kantenlänge von 0 Abziehen, für 2. dazuaddieren
            'Reihenfolge Eckpunktangabe gegen Uhrzeigersinn VON UNTEN her gesehen (unten=Außenseite später)
            glColor3f  Farbe5Rot        , Farbe5Gruen      , Farbe5Blau
            glVertex3f 0-(XLaenge/2)    , 0  , 0+(ZLaenge/2)
            glVertex3f 0-(XLaenge/2)    , 0  , 0-(ZLaenge/2)
            glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2)
            glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2)
         glEnd
         glBegin GL_TRIANGLES
            '   Dreieckseite 1 =an Kante 1.+2.Quadratpunkt
            glColor3f  Farbe1Rot        , Farbe1Gruen      , Farbe1Blau
            glVertex3f 0-(XLaenge/2)    , 0       , 0-(ZLaenge/2)
            glVertex3f 0-(XLaenge/2)    , 0       , 0+(ZLaenge/2)
            glVertex3f 0                , YLaenge , 0
            '   Dreieckseite 2 =an Kante 2.+3.Quadratpunkt
            glColor3f  Farbe2Rot        , Farbe2Gruen      , Farbe2Blau
            glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2)
            glVertex3f 0-(XLaenge/2)    , 0  , 0-(ZLaenge/2)
            glVertex3f 0                , YLaenge , 0
            '   Dreieckseite 3 =an Kante 3.+4.Quadratpunkt
            glColor3f  Farbe3Rot        , Farbe3Gruen      , Farbe3Blau
            glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2)
            glVertex3f 0+(XLaenge/2)    , 0  , 0-(ZLaenge/2)
            glVertex3f 0                , YLaenge , 0
            '   Dreieckseite 4 =an Kante 3.+1.Quadratpunkt
            glColor3f  Farbe4Rot        , Farbe4Gruen      , Farbe4Blau
            glVertex3f 0-(XLaenge/2)    , 0  , 0+(ZLaenge/2)
            glVertex3f 0+(XLaenge/2)    , 0  , 0+(ZLaenge/2)
            glVertex3f 0                , YLaenge , 0
         glEnd
      CASE ELSE
         'Hier kommen alle SUB-Aufrufe an, welche als
         'was-Parameter einen Eintrag haben, der hier
         'nicht ausgewertet wurde.
         'Tippfehler vom Programmierer????
   END SELECT
END SUB

Ist doch schon ganz interessant? Die Kamera bewegen, die Pyramiden drehen, egal, wo wir mit der Kamera hinfahren, die Pyramide drehen sich auf Tastendruck...

Aber eigentlich wollten wir die Kamera und nicht die Pyramide drehen? Blättern Sie um, dann gehen wirs an.

 

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