• 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
    [autoit]

    ; Projection
    glFrustum($fLeft, $fRight, $fBottom, $fTop, $fNearVal, $fFarVal)
    glOrtho($fLeft, $fRight, $fBottom, $fTop, $fNearVal, $fFarVal)

    [/autoit] [autoit][/autoit] [autoit]

    ; Viewing
    glViewport($iX, $iY, $iWidth, $iHeight)

    ; Modeling
    glTranslatef($fX, $fY, $fZ)
    glRotatef($fAngle, $fX, $fY, $fZ)
    glScalef($fX, $fY, $fZ)

    [/autoit]

    -> 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)
    Perspektivische Projektion (Bild2)

    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)

    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)
    [autoit]


    Func DrawScene()
    glClear($GL_COLOR_BUFFER_BIT) ; Buffer leeren
    glLoadIdentity() ; ModelView leeren

    [/autoit] [autoit][/autoit] [autoit]

    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()

    [/autoit] [autoit][/autoit] [autoit]

    SwapBuffers($hDC) ;Anzeigen
    EndFunc

    [/autoit]

    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)
    [autoit]

    glEnable($GL_DEPTH_TEST) ; Depth Buffer an
    glClear($GL_DEPTH_BUFFER_BIT) ; Depth Buffer leeren

    [/autoit]

    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)
    [autoit]

    glEnable($GL_CULL_FACE) ; Culling für Flächen an
    glCullFace($GL_BACK) ; Rückseite cullen (/$GL_FRONT)

    [/autoit]

    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:

    [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit][autoit][/autoit][autoit]

    Global $gui = GUICreate("OpenGL", 250, 250), $dc, $rc
    GUISetOnEvent(-3, "quit")

    [/autoit]

    Nun müssen wir OpenGL hochfahren und die Zeichenfläche auf die GUI legen. Gleichzeitig überprüfen wir noch
    auf Fehler:

    [autoit]

    If Not glInit($gui, $dc, $rc) Then
    MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
    Exit
    EndIf

    [/autoit]

    Wir setzen nun den Matrix Modus. Da wir zeichnen wollen, also eine Projection erstellen wollen gehen wir in
    diesen Modus mit:

    [autoit]

    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)
    [autoit]

    While 1

    [/autoit] [autoit][/autoit] [autoit]

    glClear($GL_COLOR_BUFFER_BIT)
    glBegin($GL_LINES)

    [/autoit] [autoit][/autoit] [autoit]

    glColor3ub(0, 255, 0)

    [/autoit] [autoit][/autoit] [autoit]

    glVertex3f(0, .5, 0)
    glVertex3f(0, -.5, 0)

    [/autoit] [autoit][/autoit] [autoit]

    glVertex3f( -.5, 0, 0)
    glVertex3f( .5, 0, 0)
    glEnd()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    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():

    [autoit]

    Func quit()
    glTerminate($gui, $dc, $rc)
    Exit
    EndFunc

    [/autoit]

    Also ist unser komplettes Beispiel:

    Fadenkreuz komplett (Code5)
    [autoit]

    #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")

    [/autoit] [autoit][/autoit] [autoit]

    If Not glInit($gui, $dc, $rc) Then
    MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    glColor3ub(0, 255, 0)

    [/autoit] [autoit][/autoit] [autoit]

    glVertex3f(0, .5, 0)
    glVertex3f(0, -.5, 0)

    [/autoit] [autoit][/autoit] [autoit]

    glVertex3f( -.5, 0, 0)
    glVertex3f( .5, 0, 0)
    glEnd()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    glSwapBuffers($dc)

    [/autoit] [autoit][/autoit] [autoit]

    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func quit()
    glTerminate($gui, $dc, $rc)
    Exit
    EndFunc

    [/autoit]

    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)
    [autoit]

    #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")

    [/autoit] [autoit][/autoit] [autoit]

    If Not glinit($gui, $dc, $rc) Then
    MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    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)
    [autoit]

    #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")

    [/autoit] [autoit][/autoit] [autoit]

    If Not glinit($gui, $dc, $rc) Then
    MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    glEnd()

    [/autoit] [autoit][/autoit] [autoit]

    glSwapBuffers($dc)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func quit()
    glTerminate($gui, $dc, $rc)
    Exit
    EndFunc

    [/autoit]

    12.3 Verrückte Dinge

    Wir können unter OpenGl folgende Formen zeichnen:

    Primitven in OpenGl (Bild4)

    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

    [autoit]

    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

    [/autoit]

    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 )
    [autoit]

    #include <gl.au3>
    #include <Math.au3>

    [/autoit] [autoit][/autoit] [autoit]

    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")

    [/autoit] [autoit][/autoit] [autoit]

    If Not glInit($gui, $dc, $rc) Then
    MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 360 Step 360/$CircleStacks
    $x = .5 * Sin(_Radian($i))
    $y = .5 * Cos(_Radian($i))
    glVertex3f($x,$y,0)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    glEnd()
    glSwapBuffers($dc)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func quit()
    glTerminate($gui, $dc, $rc)
    Exit
    EndFunc

    [/autoit]

    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)
    [autoit]

    #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")

    [/autoit] [autoit][/autoit] [autoit]

    If Not glinit($gui, $dc, $rc) Then
    MsgBox(48, "Error", "Error bei der Initialisierung von OpenGL-Funktionen" & @CRLF & "Error code: " & @error)
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    glMatrixMode($GL_PROJECTION)
    glEnable($GL_DEPTH_TEST)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While 1
    glClear($GL_COLOR_BUFFER_BIT + $GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()

    [/autoit] [autoit][/autoit] [autoit]

    glRotatef(45, 1, 0, 1)
    glRotatef($rotation, 0, 1, 0)

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    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()

    [/autoit] [autoit][/autoit] [autoit]

    $rotation = $rotation + 0.5

    [/autoit] [autoit][/autoit] [autoit]

    glSwapBuffers($dc)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func quit()
    glTerminate($gui, $dc, $rc)
    Exit
    EndFunc

    [/autoit]

    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 :D

    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

    Irrlicht - OpenGL - DirectX - Tiny3D - au3impact

    mfG, minx :thumbup:

  • Würde es dafür eine Hilfe geben, wäre des Perfekt!
    Aber schönes Tutorial,
    schön gegliedert und schön ausgedrückt,
    bloß die erklärung der Scripte haben mir etwas gefehlt,
    zB. warum du '.5' nimmst, sind aber nur kleinigkeiten.
    (Daumen Hoch)

    MfG

  • Eine Hilfe. Na vielleicht irgendwann ^^. Wie gesagt man kann eigentlich jedes OpenGl Tutorial nehmen, für zum Beispiel BASIC oder sonstwas. Die Syntax ist ja eigentlich gleich. :D

    Deine Frage ist zum FAQ hinzugefügt.

    Übrigens bei Absatz 2: "Eigentlich sehr einfach. Die floats dürfen im Übrigen von 0.00 bis 1.00 gehen." Damit hat das Zeichenfeld ein Maß von 1.00 in jede Richtung.

  • Wie schnell zeichnet GL komplexere "formen"? also framerate ;)

    Sind TV-Quizfragen zu einfach? A) Ja B) Harry Potter

    Spoiler anzeigen

    Ich gebe zu dieser Post hat wahrscheinlich nicht viel geholfen,
    aber ich versuche wenigstens zu helfen :rolleyes:

  • OpenGl rechnet DIREKT in der Grafik. Also so schnell es geht ;). Ich habe mal eine Welt aus über 22.000 Voxeln (Würfel und Kanten) erstellt. Das dauert so vielleicht 2s. Also es ist auf jeden Fall sehr schnell. Mit DirectX das Schnellste was es gibt. Rechnungen sollte man natürlich immer mit ASM machen und es kommt auch auf die Effizienz deiner Funktionen an.

    Es ist einfach ein Standard. Bekannte riesen Spiele nutzen entweder OpenGl oder DirectX als Renderer. Es kommt halt auf die Engine an, die du selbst machst ;)

  • Erstmal: Wow!
    Ein richtig gutes Tutorial, dass für die Komplexität des Themas relativ leicht zu verstehen ist :thumbup:

    Allerdings habe ich dazu noch 2 Fragen:
    1. Was ist der Unterschied zwischen den beiden Funktionen glColor3ub() und glColor3f() ?Beide machen ja im Grunde das gleiche, wenn man sie z.b.in dein Kreisbeispiel einsetzt ?(
    2. Da das Thema interesse geweckt hat: Gibt es eine (möglichst deutsche) Seite bei der alle/die wichtigsten Funktionen kurz beschrieben werden wie z.b. das einbinden von Texturen,... ?

  • Danke :D

    Zur 1. Frage:
    glColor3ub() benutzt Werte im Raum von 0 bis 255, also Integer. glColor3f() benutzt Werte mit Floats, also von 0.00 bis 1.00. Ein Beispiel für ein rotes Feld:

    - glColor3ub(255,0,0)
    - glColor3f(1, 0, 0)

    immer im R(ot) G(rün) B(lau) - Raum ;)

    Zur 2. Frage:
    Bemüh mal Google nach OpenGl Basic Tutorial oder so. Vielleicht VB6 Tuts oder so, die kommen dem AutoIt Syntax schon sehr nahe ^^.

  • Habe hier schon lange nicht mehr reingeschaut ... und wow! - Endlich mal jemand, der sich unter AutoIt mit der Grafik-Programmierung "OpenGL" auseinandersetzt. Leider habe ich monentan keine Zeit mich eingehender auch noch damit zu beschäftigen - aber aufgeschoben ist nicht aufgehoben!

    Bei meinem z.Zt. ruhenden Projekt "Wir bauen uns ein CAD" hatte ich diese Problematik auch schon mal erwähnt und auch die Hoffnung gehegt, dass sich mal jemand mit DirectX unter AutoIt beschäftigt. Wäre sicherlich für die Spiele-Programmierer unter den AutoIt-Usern eine lohnende Aufgabe...

    Grüsse aus Berlin

    PSblnkd

  • Danke :D

    Ein DirectX Tutorial wird folgen. Meine neue Engine Dash baut ganz auf DirectX auf ;). Die gibt es dann nächstes Jahr. Für CADs ist OpenGl aber auf jeden Fall sinnvoller als DirectX, du kannst ja gleichzeitig noch OpenCl von Andy anschauen, dann kannst du wirklich beeindruckende Sachen machen.

    Ich habe übrigens vor kurzer Zeit auch mal ein 3D CAD zusammengezimmert (mit OpenGl)

    Screenshot

    Das Speichern, Modellieren und öffnen funktioniert soweit, aber ich habe irgendwie die Lust verloren, weil ich erkannt habe, dass ich eine Strukturfehler gemacht habe :D

    MfG

    Einmal editiert, zuletzt von minx (2. Dezember 2012 um 12:20)

  • Was soll daran richtig sein, dass die Ebenen ausgeblendet werden ?! Bzw überblendet
    €: 2. Was hast du eigentlich an der GL.au3 gemacht ? Welche Funktion daran ist von dir ?

    Es gibt sehr viele Leute, die glauben. Aber aus Aberglauben.
    - Blaise Pascal

  • Dann mach bitte ein besseres Beispiel :). Ich habe oben beschrieben was ich gemacht habe: Die Funktionen zusammengetragen und einige Änderungen vorgenommen die den Umgang leichter machen. Alle Autoren die ich finden konnte sind auch in der UDF vermerkt, also was soll die Frage?

    Wenn du was zu besseres hast das schick es mir einfach. Das Beispiel ist so verfasst, das man es leicht verstehen kann, weil es sich fast ausschließlich auf den Würfel beschränkt.

  • Du solltest in dem Cube Beispiel ne andere Matrix und kein Frustum nehmen ...


    Es fehlt doch nur "glEnable($GL_DEPTH_TEST)".

    E: minx: Bevor ich's wieder vergesse: Der Plural von "Vertex" lautet "Vertices".

  • Oh, da fällt mir auf das Ich die alten Scripte hochgeladen habe, sorry Xori & Core ;)

    Das Beispiel ist geupdated! Danke für den Hinweis!

    Einmal editiert, zuletzt von minx (2. Dezember 2012 um 19:06)

  • Gut :D
    @Centu - Ich habe vor fast 1 Jahr das letzte mal mit OpenGL (in C++) gearbeitet, deshalb war ich mir nicht sicher was es war ...
    minx - Ne, ich hatte mich das nur gefragt weil die auf mich genau so wie die anderen wirkt ;D

    Es gibt sehr viele Leute, die glauben. Aber aus Aberglauben.
    - Blaise Pascal

  • So ich habe jetzt fast alles beisammen und mich mal durch die OpenGl Welt gewütet.

    Nächstes Jahr gibt es ein neues, viel (viel) größeres Tutorial und eine riesige deutsche Hilfe zu der neuen UDF: ogl4au3 2.0.
    Es gibt massig viel neues, einfaches und schweres aber gutes! Wie: Licht, Material, Listen, Texturen, Shader und Image Unterstützung, volle Win7 + Ubuntu + OSX Kombatibilität, neue UDF Header, neue Logik, schnellere Funktionen und besseres Handling.

    Dieses Tut wird dann leider ausgedient haben, da sich auch der Syntax etwas ändert. Wenn es fertig ist, kann man mit OpenGl riiiichtig viel anstellen- Der Plan es mit Andys OpenCL zusammenzulegen besteht auch noch.

    Also: Freuhet euch :thumbup:

  • Hört sich nett an, bin mal gespannt
    auch wenn auf dem bild die 3D berechnung optisch nicht so gut wie ein Würfel aussieht, naja liegt vlt am screen & an der Textur.

    Sind TV-Quizfragen zu einfach? A) Ja B) Harry Potter

    Spoiler anzeigen

    Ich gebe zu dieser Post hat wahrscheinlich nicht viel geholfen,
    aber ich versuche wenigstens zu helfen :rolleyes: