Tutorial
OpenGL und FreeBASIC - eine kleine Einführung - Teil 4 - Rotieren
von Eastler_dart | Seite 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:
ParaNr | Bedeutung |
---|---|
1 | Gradzahl |
2 | um X drehen? |
3 | um Y drehen? |
4 | um 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
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 Open-Befehl - mit Open die Konsole für Ausgabe öffnen, mit Print # 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:
- mit jedem x- und X-Tastendruck die Pyramide um die X-Achse ein Grad vor- und zurückdrehen
- mit jedem y- und Y-Tastendruck die Pyramide um die Y-Achse ein Grad vor- und zurückdrehen
- mit jedem z- und Z-Tastendruck die Pyramide um die Z-Achse ein Grad vor- und zurückdrehen
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:
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.
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|
|