[Blockierte Grafik: http://s14.directupload.net/images/121217/6gcjtxek.png]
Palim, palim!
Jetzt möchte ich auch mal mein erstes "richtiges" Tutorial schreiben. Es geht sich hierbei im OpenGl.
1. Was ist OpenGl?
OpenGL (Open Graphics Library) ist eine Spezifikation für eine plattform- und
programmiersprachenunabhängige Programmierschnittstelle zur Entwicklung von 2D- und 3D-Computergrafik.
Der OpenGL-Standard beschreibt etwa 250 Befehle, die die Darstellung komplexer 3D-Szenen in Echtzeit erlauben.
Zudem können andere Organisationen (zumeist Hersteller von Grafikkarten) proprietäre Erweiterungen definieren.
1.1 In welcher Form liegt OpenGl uns bereit?
Da wir mit AutoIt und Windows programmieren, so ist nur die von Microsoft vorgestellte Ordnung relevant. Unter
Windows steht und OpenGl in Form einer DLL Bibliothek zur Verfügung. Zur Angenehmeren Bearbeitung mit
AutoIt benutzen wir aber eine UDF.
1.2 EINE UDF...
Unbestimmter Artikel. Es gibt eben nicht nur DIESE UDF, mit der wir uns zufrieden geben können. Anfangs bestand
die Unterstützung von OpenGl für AutoIt aus einer bloßen Liste von DLL Calls. Dann haben mehr als ein Dutzend
User die verschiedensten Dinge zusammengezimmert. Einige mit anderen UDFs, anderen DLLs, als Plugin usw.
Das Problem ist: Bei allen funktioniert irgendwas nicht richtig.
Aus diesem Grund habe ich mich mal durch die Berge an Code gewühlt, VORBEI an gfwl, soil, glut und Konsorten, um
einfach erst einmal den Umgang zu erleichtern, und mich ganz auf OpenGL beschränkt. Entstanden ist eine grooooße
Datei mit nahezu allen Funktionen der opengl32.dll und ebenso, nahezu allen Konstanten.
Mit DIESER UDF ist nun ein nahezu natloses Übersetzen von OGl Quelltext aus anderen Sprachen nach AutoIt
möglich, man muss dabei nicht groß umdenken, und kann so fast jedes OGl Tutorial benutzen. (Aber jetzt erstmal
hiergeblieben! )
2. Die Befehle
Die Befehle für OpenGl sind in jeder Sprache gleich und beginnen mit "gl". Untersuchen wir mal einen kleinen
Befehl: "glVertex3f". Dieser Befehl gibt uns in 4 Dingen Auskunft:
1. gl -> opengl32.dll
2. Vertext -> Es geht um die Erstellung eines Vertex, also einen Punkt im Raum. Dies ist der Funktionsname
3. 3 -> Zahl der Parameter
4. f -> Die Zahlen sind floats
Wenden wir das an. Wir wollen also einen Punkt mit den Koordinaten, sagen wir, (0|0|0) zeichnen, also genau
mittig. Dann wäre der Syntax in AutoIt: "glVertex3f(0,0,0)".
Eigentlich sehr einfach. Die floats dürfen im Übrigen von 0.00 bis 1.00 gehen.
3. Konzept der statischen Werte
Wenn im Skript einmal etwas festgelegt wird, zum Beispiel mit "glColor3f(1,0,0)", die Farbe auf Rot, so ver-
bleibt diese Einstellung bis man erneut diesen Befel mit anderen Paramtern aufruft.
4. Primitiven
OpenGl arbeitet mit Primitiven, wird deshalb auch Low Level 3D Engine genannt. WIr können damit also Punkte, Linien,
Dreiecke, Quadrate und Polygone zeichnen. (Ja, richtig, keine Kreise oder 3D Objekte).
5. Vertexe
Alle Primitven müssen von uns aus Vertexen aufgebaut werden. Wir haben mehrere Befehle um solche Vertexe im
Raum zu generieren, aber der Wichtigste für uns ist: "glVertex3f(xf,yf,zf)".
Wir brauche immer die Ecken der Primitven, das heißt also wir benötigen für einen Punkt einen Vertex, für eine
Linie 2, für ein Dreieck 3 und so weiter. Geben wir 4 Vertexe hintereinander an, und haben den "Linienstyle"
drin, so werden zwei Linien, eine vom 1. bis zum 2. und eine vom 3. bis zum 4. Punkt erstellt. Also nimmt
uns hier OGl etwas Arbeit ab.
6. Farben
Farben sind so eine Sache in OepnGl. Wir haben hier hauptsächlich zwei Möglichkeiten die Farbe für die nach-
folgenden Befehle zu setzen. Zum Beispiel im 3f Raum:
- glColor3f(rf,gf,bf) -> Die Zahlen werden hier als floats angegeben
- glColor3ub(r,g,b) -> Zie Zahlen werden jetzt von 0 bis 255 angegeben
Wenn alle Vertexe die gleiche Farbe haben, hat das Primitiv als Ganzes auch diese Farbe. Beispiel: 4 Rote
Vertexe im Quadstyle erzeugen ein rotes Quadrat.
Wenn die Farben unterschiedlich sind, müssen wir festlegen was passieren soll. Dies tun wir mit
"glShadeModel($Style)"
- $GL_FLAT -> Für Linien/Dreiecke die Farbe des letzten Vertex, für Quads die des Ersten
- $GL_SMOOTH -> Interpolierter Farbverlauf zwischen allen Vertexen
7. Koordinaten
Die Koordinaten im Zeichenfeld sind etwas anders als in einer normalen GUI. x0, y0 beschreiben jetzt den Mittel-
punkt des Fensters und die Z-Achse "ragt" aus dem Bildschirm dem Betrachter entgegen. Positive Rotationen
um Achsen erfolgen stets entgegengesetzt dem Uhrzeigersinn.
8. Der Viewport
Der Viewport ist ein rechteckiger Ausschnitt der Gesamtzeichenfläche, die am Ende definiert, was der Benutzer
sieht. Also sozusagen das "Fenster" zur gezeichneten Welt. Normalerweise, wenn man nichts festlegt, so nimmt der
Viewport die ganze Zeichenfläche ein. Das ganze wird angegeben wie bei einem Control, obwohl hier der Start-
punkt unten Links ist. Also x0, y0 vom Viewport ist die linke untere Ecke. Der Befehl ist hier:
"glViewport(x,y,w,h)"
9. Transformationen
OpenGl bietet viele Möglichkeiten eine 3D Szene zu verändern. Dies nennt man Transformation. Transformation reicht
von dem totalen Verändern einer Szene bis hin zum einfachen setzen des Viewpunkts. Die Transformations-
befehle werden in 3 Typen eingeteilt:
9.1 Projektion
Diese Befehle brauchen wir, um eine 3D Szene auf unseren 2D Bildschirm abzubilden. Dabei wird perspektivische
und orthographische Abbildung unterstützt. Bei einer orthographischen Darstellung entfällt der Schrumpf-
effekt bei weiter hinten liegenden Obejkten im Raum (-> die Perspektive).
9.2 Viewing
Wir gehen bei OpenGl "Kameras" immer von Beobachtern aus, die immer einen Standpunkt und einen punkt haben, auf
den sie schauen. (Ähnlich wie bei DirectX mit dem Eye Vector). Die Viewing Befehle manipulieren diese Punkte.
9.3 Modeling
Wohl der wichtigste Transformationstyp. Mit diesen Befehlen können wir Objekte in der Szene bewegen (move),
rotieren (rotate) und deren Größe ändern (scale).
Bevor wir uns nun noch einmal genauer mit der etwas komplexen Transformation befassen, hier mal kurz die Befehle:
Transformationen
; Projection
glFrustum($fLeft, $fRight, $fBottom, $fTop, $fNearVal, $fFarVal)
glOrtho($fLeft, $fRight, $fBottom, $fTop, $fNearVal, $fFarVal)
; Viewing
glViewport($iX, $iY, $iWidth, $iHeight)
; Modeling
glTranslatef($fX, $fY, $fZ)
glRotatef($fAngle, $fX, $fY, $fZ)
glScalef($fX, $fY, $fZ)
-> 9.1 Über das Transformieren der Projektion.
OpenGl arbeitet mit dem Prinzip eines 3D Sichtfeldes, das durch einen Körper definiert wird (View Volume).
Alles in diesem Volume wird angezeigt, alles andere nicht. WIr unterscheiden zwischen Orthographisch
(Parallele Projektion) und die Perspektivische Projektion.
Parallele Projektion (Bild1)
[Blockierte Grafik: http://www.csee.umbc.edu/~rheingan/435/…iew/view2-3.gif]
Perspektivische Projektion (Bild2)
[Blockierte Grafik: http://www.csee.umbc.edu/~rheingan/435/…iew/view2-5.gif]
In der Parallelen Projektion ist das Volume einfach eine Box, ein Quader im Raum, das bedeutet praktisch, das
die Distanz der Objekte in diesem Volume zum Beobachter keinen Größenunterschied aufweisen. Der Flucht-
effekt entfällt. Benutzt wird diese, auf den ersten Blick sinnlose, Darstellung für architektonische Pläne
und Blaupausen, bei denen die Proportionen der projezierten Objekte erkennbar sein muss.
Bei der Perspektivischen Projektion ist das Volume ein Stumpf (zu englisch: frustum), also haben wir hier
eindeutig einen Fluchteffekt, der die ganze Szene real und tief erscheinen lässt. Einfach wie unsere Augen
funktionieren. Auf diesen Modus beschränken wir uns. Die Sichtweite ist aber wichtig. Ein (Pyramiden)stumpf ist
ein Ausschnitt aus der Grundfigur (Pyramide), der zwischen zwei parallelen Deckflächen definiert ist.
Die dem Beobachter zugewandte Deckfläche heißt "Near Plane" und die dahinter "Far Plane". Man kann nun die Sicht-
weite definieren, in dem man festlegt, wie weit hinten die Far Plane liegen soll. Liegt sie zum Beispiel
unendlich weit hinten, so werden alle Objekte, die perspektivisch vor dieser Plane liegen, dargestellt.
Skizze des Fluchtsystems - Fluchtpunkt A in der Mitte (Bild3)
[Blockierte Grafik: http://www.klassentagebuch.de/4456.jpg]
Wir erinnern uns an die Befehle:
- glOrthographic - Paralleles Volume
- glFrustum - Damit erstellen wir einen unregelmäßigen Stumpf
Default ist die Perspektivische Projektion gesetzt, und das lassen wir mal so, wir werden also hier nichts mehr
ändern.
-> 9.3 Über das Transformieren der Models
9.3.1 glTranslatef
Wer schon einmal mit uralten 3D CAD Systemen gearbeitet hat, wird noch wissen, dass eine Bewegung eines Objektes
fast immer die Differenz fordert, das heißt um wie viel "Weg" soll das Objekt bewegt werden. Zum Beispiel:
"glTranslatef(.05,0,0)" verschiebt das Objekt um .05 in X-Richtung.
9.3.2 glRotatef
Dieser Befehl rotiert das Objekt. Dabei wird erst der Winkel angegeben, und dann ein boolscher Wert für die Achsen.
Wenn das Objekt jetzt also zum Beispiel um 30° um die X-Achse rotiert werden soll, so lautet der Syntax:
"glRotatef(30, 1, 0 , 0".
10. Matrizen
Jetzt können sich die freuen, die keine Matrixrechnung beherrschen! Denn OpenGl verwendet zwar laufend Matrizen,
aber nimmt uns die Rechnung damit völlig ab.
OpenGl nutzt für die Speicherung des Status einer Szene drei Matrizen: ModelView, Projection und Texture.
Es kann zu einem Zeitpunkt immer nur EINE Matrix angewählt sein, um darin Änderungen vorzunehmen. Wir sehen
uns mal kurz die Modi an:
- ModelView - Primitiven zeichnen und verändern
- Projection - Perspektive verändern
- Texture - Material für Primitiven festlegen
Wie verfahren wir mit Matrizen? Schritt für Schritt:
1. Auswählen der Matrix
2. Matrix leeren
3. Verändern von irgendwas
4. Anzeigen
Für Codeabfolge, und das ist jetzt sehr wichig, müssen wir folgend verfahren:
1. Matrix auswählen
2. Matrix leeren
3. Zeichenfeld leeren
4. Paramter setzen (Rotation, ...)
5. Primitiven zeichnen
6. Anzeigen
10.1 Matrix Stack
Ein Stack ist ein Stapelspeicher. Man muss ihn sich vorstellen wie ein Stapel Papier, auf dem Eigenschaften ge-
speichert sind und wieder geladen werden können. Dieses Speichern und Lesen bei Stacks nennt man Push und Pop.
Die Befehle dazu sind:
- glPushMatrix
- glPopMatrix
Mit diesen Befehlen kommunizieren wir mit dem automatisch angelegten Stack.
Lest euch bitte erstmal diesen Code durch, ich weiß, dass wir noch nicht alle Befehle besprochen haben, aber
es geht um die Struktur und den Aufruf der Stack Kommandos:
Matrix Stack (Code1)
Func DrawScene()
glClear($GL_COLOR_BUFFER_BIT) ; Buffer leeren
glLoadIdentity() ; ModelView leeren
glPushMatrix() ;Speichert alle Einstellung der aktuellen Matrix
[/autoit] [autoit][/autoit] [autoit]glRotatef(25,1,1,1) ; Rotieren
glBegin($GL_POINTS)
glVertex3f(0,0,0) ;Rotierten Punkt erstellen
glEnd()
glPopMatrix() ;Alte Einstellungen laden (Keine Rotation...)
glRotatef(40,1,1,1)
glBegin($GL_POINTS)
glVertex3f(1,1,0) ;Rotierten (40°) Punkt erstellen
glEnd()
SwapBuffers($hDC) ;Anzeigen
EndFunc
Würden wir nicht mit dem Stack arbeiten, wäre der zweite Vertex 2x(!) rotiert worden! Beachtet das! Schafft euch
am Besten immer einen Ausgangszustand, auf den ihr dann im Stack zurückgreifen könnt, das erleichtert das
Arbeiten.
Man, war das ein langer Punkt ...
11. Optimierung
Wir haben gleich 3 Optionen um das Aussehen unserer Szene zu verbessern, was natürlich erst für größere Welten
relevant ist. Alle Optionen sind sinnvollerweise by default ausgeschaltet, um die Performance zu verbesser.
Folgende Optionen können wir nutzen:
- Doublebuffer - Das Prinzip ist klar. Alles wird auf eine 2., unsichtbare Fläche gezeichnet und dann angezeigt
- HSR (Hidden Surface Removal) - verbessert die Performance, indem nicht beobachtbare Flächen nicht gezeichnet
werden
- Culling - Wie bei DirectX ist hiermit das selektive Zeichnen gemeint. Das heißt nach hinten gerichtete Flächen
werden z.B. nicht gezeichnet
11.1 Double Buffer
Der Double Buffer, für alle die noch nie etwas davon gehört haben, erzeugt ein Back Interface, also eine für
den User unsichtbare Zeichenfläche, auf die gezeichnet wird, während die erste noch angezeigt ist. Ist das
Hintergrundzeichnen fertig werden die Buffer geswapt, also getauscht und alles geht von vorn los. Das ist etwas
Ressourcenlastig, aber nötig für eine flüssige Animation und in meiner UDF immer aktiviert.
Double Buffer wird von der Windows API verwaltet und bezieht sich somit auf den Fensterkontext, nicht auf den
Renderkontext. In der Hauptschleife wird einfach ein "glSwapBuffers" angehängt. Dies wird aus der GDI32.dll be-
zogen und ist somit keine Standard OpenGl32.dll Funktion! GDI muss vorhanden sein!
11.2 HSR
Obwohl wir eine 2D Zeichenfläche haben, können wir einen Z-Buffer, also einen Tiefenbuffer für jeden Pixel hin-
zufügen. Was? Ganz einfach: bevor ein Pixel eines Objektes gezeichnet wird, wird ein Vergleich mit dem
Tiefenbufferwert des Pixels angestellt. Wenn der neue Pixel näher am Near Panel liegt, also vor diesem Wert,
wird der Buffer mit den neuen Daten überschrieben und der Pixel wird gezeichnet. Wenn der Pixel verdeckt ist,
also der Bufferwert hinter einem anderen Pixel liegt, so wird er nicht gezeichnet, aber der Buffer bleibt
erhalten.
HSR (Code2)
glEnable($GL_DEPTH_TEST) ; Depth Buffer an
glClear($GL_DEPTH_BUFFER_BIT) ; Depth Buffer leeren
11.3 Culling
Eine Fläche hat zwei Seiten. Ein Primitv, zum Beispiel ein Quadrat hat eine Vorder- und eine Rückseite. Die
Rückseite müssen wir ja eigentlich nicht zeichnen. Diese Flächen von der Zeichenroutine auszuschließen heißt
Culling.
Culling (Code3)
glEnable($GL_CULL_FACE) ; Culling für Flächen an
glCullFace($GL_BACK) ; Rückseite cullen (/$GL_FRONT)
12. Beispiele
Fck yeah! Wir haben den ganzen Theoriemist erledigt, jetzt geht es ans Eingemachte. Klar, das wir nicht auch
noch die ganze 3D Mathe-Theorie machen wollen (zumindes ich nicht). Dafür gibt es andere Hilfen und das eigene
Gehirn
Übrigens: Das Zeichenfeld hat die Maße -1 bis 1. Also ein Koordinatensystem mit den Maßen 1 in jede Richtung. Deshalb verwenden wir Werte von 0.00 bis 1.00!
12.1 Erste Gehversuche
Um jetzt irgendwas zu machen, beginnen wir erstmal mit dem Include.
[autoit]#include <gl.au3>
[/autoit]Danach brauchen wir einen Container für die Zeichenfläche. Das ist eine ganz normale GUI, es kann sogar eine
Child GUI sein. Diese benutzen wir im Eventmodus. Desweiteren brauchen wir noch zwei freie Variabeln:
$dc und $rc für Handles. Also:
Opt("GUIOnEventMode", 1)
[/autoit][autoit][/autoit][autoit]Global $gui = GUICreate("OpenGL", 250, 250), $dc, $rc
GUISetOnEvent(-3, "quit")
Nun müssen wir OpenGL hochfahren und die Zeichenfläche auf die GUI legen. Gleichzeitig überprüfen wir noch
auf Fehler:
If Not glInit($gui, $dc, $rc) Then
MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
Exit
EndIf
Wir setzen nun den Matrix Modus. Da wir zeichnen wollen, also eine Projection erstellen wollen gehen wir in
diesen Modus mit:
glMatrixMode($GL_PROJECTION)
[/autoit]Jetzt zeigen wir noch die GUI an. Dann haben wir Platz zum Zeichnen!
[autoit]GUISetState()
[/autoit]In unsere Schleife kommt jetzt die Zeichnung. Wir wollen jetzt 2 Linien zeichen. Wir leeren erst den Buffer,
stellen auf Linien um, setzten eine Farbe und geben dann 4 Punkte an. OpenGl erkennt automatisch, dass es 4
Punkte sind, aber nur 2 pro Linie gebraucht werden. So wir eine Linie vom 1. zum 2. und vom 3. zum 4. ge-
zeichnet. Dann beenden wir die Zeichnung und swappen die Buffer!
Schleife mit Zeichnung (Code4)
While 1
[/autoit] [autoit][/autoit] [autoit]glClear($GL_COLOR_BUFFER_BIT)
glBegin($GL_LINES)
glColor3ub(0, 255, 0)
[/autoit] [autoit][/autoit] [autoit]glVertex3f(0, .5, 0)
glVertex3f(0, -.5, 0)
glVertex3f( -.5, 0, 0)
glVertex3f( .5, 0, 0)
glEnd()
glSwapBuffers($dc)
[/autoit] [autoit][/autoit] [autoit]WEnd
[/autoit]Nun brauchen wir noch die definierte Quit-Funktion. Dabei müssen alle Handles wieder freigegeben werden und das
Programm beendet. Das erste übernimmt alles die UDF. Die Funktion wird genauso aufgerufen wie glInit():
Func quit()
glTerminate($gui, $dc, $rc)
Exit
EndFunc
Also ist unser komplettes Beispiel:
Fadenkreuz komplett (Code5)
#include <gl.au3>
[/autoit] [autoit][/autoit] [autoit]Opt("GUIOnEventMode", 1)
[/autoit] [autoit][/autoit] [autoit]Global $gui = GUICreate("OpenGL", 250, 250), $dc, $rc
GUISetOnEvent(-3, "quit")
If Not glInit($gui, $dc, $rc) Then
MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
Exit
EndIf
glMatrixMode($GL_PROJECTION)
[/autoit] [autoit][/autoit] [autoit]GUISetState()
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]While 1
[/autoit] [autoit][/autoit] [autoit]glClear($GL_COLOR_BUFFER_BIT)
glBegin($GL_LINES)
glColor3ub(0, 255, 0)
[/autoit] [autoit][/autoit] [autoit]glVertex3f(0, .5, 0)
glVertex3f(0, -.5, 0)
glVertex3f( -.5, 0, 0)
glVertex3f( .5, 0, 0)
glEnd()
glSwapBuffers($dc)
[/autoit] [autoit][/autoit] [autoit]WEnd
[/autoit] [autoit][/autoit] [autoit]Func quit()
glTerminate($gui, $dc, $rc)
Exit
EndFunc
12.2 Farbverlauf und Viereck
Ein Quadrat unter OpenGl ist eigenlich nur ein Viereck, das heißt, es muss nicht regelmäßig sein.
Wir starten wieder Opengl:
Init (Code6)
#include <gl.au3>
[/autoit] [autoit][/autoit] [autoit]Opt("GUIOnEventMode", 1)
[/autoit] [autoit][/autoit] [autoit]Global $gui = GUICreate("OpenGL", 250, 250), $dc, $rc
GUISetOnEvent(-3, "quit")
If Not glinit($gui, $dc, $rc) Then
MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
Exit
EndIf
glMatrixMode($GL_PROJECTION)
[/autoit] [autoit][/autoit] [autoit]GUISetState()
[/autoit]Dann müssen wir die Zeichnung mit $GL_QUADS beginnen und 4 Punkte festlegen. Für jeden Punkt legen wir vorher
noch eine andere Farbe fest. Wir wollen mal alle Farben, also RGB verwenden und noch eine. Gelb nehmen wir mal.
Gelb ist ja bekanntlich RG. Dann fügen wir noch die Quit-Funktion an, und fertig!
Beispiel Farbverlauf komplett (Code7)
#include <gl.au3>
[/autoit] [autoit][/autoit] [autoit]Opt("GUIOnEventMode", 1)
[/autoit] [autoit][/autoit] [autoit]Global $gui = GUICreate("OpenGL", 250, 250), $dc, $rc
GUISetOnEvent(-3, "quit")
If Not glinit($gui, $dc, $rc) Then
MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
Exit
EndIf
glMatrixMode($GL_PROJECTION)
[/autoit] [autoit][/autoit] [autoit]GUISetState()
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]While 1
[/autoit] [autoit][/autoit] [autoit]glClear($GL_COLOR_BUFFER_BIT)
[/autoit] [autoit][/autoit] [autoit]glBegin($GL_QUADS)
[/autoit] [autoit][/autoit] [autoit]glColor4f(1, 0, 0, 0)
glVertex4f(0, .5, 0, 1)
glColor4f(0, 1, 0, 0)
glVertex4f( -.5, 0, 0, 1)
glColor4f(1, 1, 0, 0)
glVertex4f(0, -.5, 0, 1)
glColor4f(0, 0, 1, 0)
glVertex4f( .5, 0, 0, 1)
glEnd()
[/autoit] [autoit][/autoit] [autoit]glSwapBuffers($dc)
WEnd
Func quit()
glTerminate($gui, $dc, $rc)
Exit
EndFunc
12.3 Verrückte Dinge
Wir können unter OpenGl folgende Formen zeichnen:
Primitven in OpenGl (Bild4)
[Blockierte Grafik: http://www.naturewizard.com/Tutorials/Tuto…es/image009.jpg]
Wir sehen, da sind zum Beispiel kombinierte Formen dabei. Die sollte man immer anstatt der einzelnen verwenden,
sie werden nämlich schneller gerendert.
Aber wir haben ein Problem! Es gibt keine Kreise. Überlegen wir mal, aus was wir einen Kreis aufbauen können.
Entscheiden wir uns mal der Freundlichkeit zur Grafikkarte halber für Dreiecke. Wir haben ein nützliches
Primitiv: Den Triangle Fan. Ein Kreis ist nichts anderes als ein Triangle Fan mit so vielen Ecken, dass er
rund aussieht. Dazu müssen Punkte, so viele wie wir wollen, alle mit gleichen Abstand in einer Kreisbahn
erstellt werden. Diese Punkte nennt man nun Stacks, oder Sticks. Wir brauchen also eine Variable
Local $CircleStacks = 50
[/autoit]Wir können theoretisch 360 Stacks im Kreis unterbringen, müssen wir aber nicht. 50 reichen locker. Wie man
die Punkte berechnet sollte klar sein. Allerdings müssen wird die Winkel umrechnen, dazu brauchen wir die
Funktion "_Radian" aus der Math.au3.
Die Zeichenfunktion sieht also so aus:
[autoit]For $i = 0 To 360 Step 360/$CircleStacks
$x = .5 * Sin(_Radian($i))
$y = .5 * Cos(_Radian($i))
glVertex3f($x,$y,0)
Next
Nun wars das schon. Noch aufräumen und so weiter und fertig ist der Kreis. Je weniger Stacks der Kreis nun hat,
desto unrunder (=zackiger) sieht er aus.
Beispiel Kreis komplett (Code8 )
#include <gl.au3>
#include <Math.au3>
Opt("GUIOnEventMode", 1)
[/autoit] [autoit][/autoit] [autoit]Local $CircleStacks = 50
[/autoit] [autoit][/autoit] [autoit]Global $gui = GUICreate("OpenGL", 250, 250), $dc, $rc
GUISetOnEvent(-3, "quit")
If Not glInit($gui, $dc, $rc) Then
MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
Exit
EndIf
glMatrixMode($GL_PROJECTION)
[/autoit] [autoit][/autoit] [autoit]GUISetState()
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]While 1
[/autoit] [autoit][/autoit] [autoit]glClear($GL_COLOR_BUFFER_BIT)
[/autoit] [autoit][/autoit] [autoit]glBegin($GL_TRIANGLE_FAN)
glColor3f(1, 0, 0)
For $i = 0 To 360 Step 360/$CircleStacks
$x = .5 * Sin(_Radian($i))
$y = .5 * Cos(_Radian($i))
glVertex3f($x,$y,0)
Next
glEnd()
glSwapBuffers($dc)
WEnd
Func quit()
glTerminate($gui, $dc, $rc)
Exit
EndFunc
12.4 Die dritte Dimension
... war die ganze Zeit schon da ^^. Wir haben vorhin gelernt, wie wir ein Rechteck zeichnen. Um nun einen Würfel
zu erstellen brauchen wir 6 Seiten, für die wir jeweils alle 4 Eckpunkte angeben müssen. Um den User
nun komplett zu verwirren, wird jede Seite ein Farbverlauf und wir rotieren den Würfel am Ende noch.
Dazu brauchen wir eine Variable, die die Rotation hält, und die wir jeden Durchlauf erhöhen. Dann rotieren wir
mit den bekannten Befehlen und ... fertig! Unsere erste 3D Szene!
3D Szene komplett (Code9)
#include <gl.au3>
[/autoit] [autoit][/autoit] [autoit]Opt("GUIOnEventMode", 1)
[/autoit] [autoit][/autoit] [autoit]Local $rotation = 0
[/autoit] [autoit][/autoit] [autoit]Global $gui = GUICreate("OpenGL", 250, 250), $dc, $rc
GUISetOnEvent(-3, "quit")
If Not glinit($gui, $dc, $rc) Then
MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
Exit
EndIf
glMatrixMode($GL_PROJECTION)
glEnable($GL_DEPTH_TEST)
GUISetState()
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]While 1
glClear($GL_COLOR_BUFFER_BIT + $GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glRotatef(45, 1, 0, 1)
glRotatef($rotation, 0, 1, 0)
glBegin($GL_QUADS)
glColor3f(0, 0, 0)
glVertex3f(-.5, -.5, -.5)
glColor3f(0, 0, 1)
glVertex3f(-.5, -.5, .5)
glColor3f(0, 1, 1)
glVertex3f(-.5, .5, .5)
glColor3f(0, 1, 0)
glVertex3f(-.5, .5, -.5)
glColor3f(1, 0, 0)
glVertex3f( .5, -.5, -.5)
glColor3f(1, 0, 1)
glVertex3f( .5, -.5, .5)
glColor3f(1, 1, 1)
glVertex3f( .5, .5, .5)
glColor3f(1, 1, 0)
glVertex3f( .5, .5, -.5)
glColor3f(0, 0, 0)
glVertex3f(-.5, -.5, -.5)
glColor3f(0, 0, 1)
glVertex3f(-.5, -.5, .5)
glColor3f(1, 0, 1)
glVertex3f( .5, -.5, .5)
glColor3f(1, 0, 0)
glVertex3f( .5, -.5, -.5)
glColor3f(0, 1, 0)
glVertex3f(-.5, .5, -.5)
glColor3f(0, 1, 1)
glVertex3f(-.5, .5, .5)
glColor3f(1, 1, 1)
glVertex3f( .5, .5, .5)
glColor3f(1, 1, 0)
glVertex3f( .5, .5, -.5)
glColor3f(0, 0, 0)
glVertex3f(-.5, -.5, -.5)
glColor3f(0, 1, 0)
glVertex3f(-.5, .5, -.5)
glColor3f(1, 1, 0)
glVertex3f( .5, .5, -.5)
glColor3f(1, 0, 0)
glVertex3f( .5, -.5, -.5)
glColor3f(0, 0, 1)
glVertex3f(-.5, -.5, .5)
glColor3f(0, 1, 1)
glVertex3f(-.5, .5, .5)
glColor3f(1, 1, 1)
glVertex3f( .5, .5, .5)
glColor3f(1, 0, 1)
glVertex3f( .5, -.5, .5)
glEnd()
$rotation = $rotation + 0.5
[/autoit] [autoit][/autoit] [autoit]glSwapBuffers($dc)
WEnd
Func quit()
glTerminate($gui, $dc, $rc)
Exit
EndFunc
13. Fazit
So das wars erstmal mit Beispielen. Jetzt dürfte alles klar sein und ihr könnt loslegen mit verrückten Sachen.
Vielleicht wäre auch eine UDF angebrahct, für Kugel, Zylinder und so weiter, wenn jemand lange Weile hat
14. FAQ
F: Warum nicht das Plugin verwenden?
A: Es ist langsam, inkompatibel mit Windows 7 und stürzt gern mal ab. Witer kann man damit auch keien Skripte
aus anderer Sprache portieren.
F: Warum OnEvent und nicht Msg?
A: Mit OnEvent wird immer die miximale Framerate erzielt. Bei Msg läuft bei Inaktivität, zum Beispiel wenn
sich die Maus nicht in der GUI bewegt, die Zeichnung auf Sparflamme
F: Warum benutzt du ".5"?
A: Ist eine ganz normale Schreibweise für 0.5 in Programmiersprachen.
F: -Hier könnte deine Frage stehen-
A: -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
15. Antworten in diesem Thread
Bitte gliedert eure Antworten in diesem Thread in zwei Teile:
1. Fragen / Anmerkungen zum Thema und auf das Tut bezogene Themen
2. Formale Fehler und Anmerkungen für das Tut, wie Rechtschreibung usw.
16. 3D Grafik Ring
mfG, minx