|
Antwort |
Hi!
Es liegt nun ja schon etwas länger zurück, dass ich hier meinen OpenGl-Kurzkurs gepostet habe und ich habe mitlererweile festgestellt, dass so mancher Fehler drinne war. Da ich nun aber auf meiner HP bereits vor einiger Zeit einen kompletten Kurs gestartet habe (zu diesem Zeitpunkt bestehend aus 8 Teilen), habe ich beschlossen als wiedergutmachung die ersten 3 Teile hier zu posten (praktisch als Wiedergutmachung für das verkorkste Kurztut.....) Leider muss ich euch sagen, dass die ganzen Bilder hier rausgefallen sind... naja: muss man mit leben (bzw: wenn es euch gefällt, könnt ihr euch ja auf www.dcw-group.net in der Coding-Sec die DOC-Files mit Bildern oder auch die Samples downloaden... Naja: viel spaß beim Reinschnuppern: (falls einigem einige Formulierungen im Bezug auf "Wochen" merkwürdig vorkommen: es handelt sich hier um die unveränderten Original-texte und da habe ich mich teilweise auf die Erscheinungsdaten der Tuts bezog en....) ------------ Teil 1 ---------- Open Gl -Delphi ? Kurs Teil 1: Was ist Open Gl Einleitung So Leute... es ist mal wieder soweit: meine neuen Tuts rücken an Allerdings ist diesmal einiges anders: Es ist nicht ein Tut, sondern ein ganzer Kurs! Das bedeutet: so etwa alle zwei Wochen erscheint ab nun ein weiterer Teil dieses Kurses, in dem es um die Open Gl ? Programmierung unter Delphi gehen soll. Ich fand diesen Schritt notwendig, da das Kurztutorial von mir bei weitem nicht die Möglichkeiten der Open Gl ? Programmierung aufgezeigt hat und, weil da die Initialisierung, die Grundlagen und die Story von Open Gl doch sehr knapp gekommen sind. Nun damit wollte ich hiermit Schluss machen, bloß ist mir dabei meine Planung derartig umfangreich geworden, dass ich das Ganze in Kurse aufspalten musst, die uns noch bis Anfang 2003 begleiten dürften... aber nun gut: lasst uns anfangen (ein großer Schritt für mich, aber ein kleiner ... ach Blödsinn... die Menschheit gammelt das hier doch gar nicht ) Was ist Open Gl An sich ne sehr gute Frage... was ist Open Gl eigentlich??? In vielen Spielen sieht man oftmals so einen netten kleinen Button, auf dem steht meist ?Software-Rendering? und oft ist daneben einer, der heißt ?Open Gl?. Die Meisten werden nach einiger Zeit feststellen, das man mit der Open Gl ? Einstellung meist besser fährt bzw. eine schönere Spielwelt erzeugt (bis auf die Armen, die null Peilung haben, und bloß nichts verändern wollen... ?läuft doch? *g*) Damit hätten wir so das Gröbste auch schon erfasst! Wie viele nun bereits festgestellt haben, ist Open Gl eine Grafikschnittstelle, dass heißt, eine Art und Weise, mit der man Grafiken auf diesen eckigen Kasten vor euch bringen kann (bei mir ist das ein grauer Röhrenbildschirm... ein 17 Zöller) Nun... was ist nun aber an Open Gl anders, als an diesem ?Software-Rendering?? Nun das ist an sich schnell erklärt: Open Gl ist ein Standart, der von praktisch allen 3d ? Grafikkarten unterstützt wird, daher ist es auch deutlich schneller, da es praktisch eine Norm darstellt. Ausgedacht hat sich diese ?Norm? die Firma ?Silicon Graphics Inc?... und das im Jahre 1988/89!!! Damals hieß das Ding aber noch ?IRIS GL? und lief nur auf den Workstations von Silicon Graphics. Aber dann wurde Silicon Graphics von dem langsam größer werdenden Anteil von Windows dazu veranlasst einen Portablen, also für fast alle Betriebssysteme brauchbaren Grafikstandart zu entwerfen... und daher geschah es: Open Gl erblickte das Licht der Welt und zwar auf der ersten ?Win. 32 Entwicklerkonferenz? in San Francisco am 19.06.92. Zu diesem Zeitpunkt war z.B. Windows NT noch in der Beta 3.1 . Seit dem gibt es also Open Gl schon, aber es ist bis heute nur bis zur Version 1.4. weiterentwickelt worden... die meisten kommen sogar mit der Urversion 1.0 klar... das liegt unter anderem daran, dass in Open Gl von vorne herein Dinge eingebaut waren, welche die damalige Hardware unter keinen umständen verarbeiten konnte... Gott sei dank, denn daher blieben viele Updates (wie sie bei Microsofts Direct X an der Tagesordnung sind) aus. Und das schönste: Open Gl wurde wie gesagt als Portable Schnittstelle konzipiert. Das heißt: man findet Open Gl auf allen Linux und Unix ? Systemen und für uns wichtig auch auf den Windows NT Systemen (ab Version 4.0) und natürlich auch auf den Windows 9x Systemen (ab Windows 95 b... Für alle die es unter Windows 95 a nutzen sollen: rennt zu eurem Nachbarn und holt euch auf Diskette die ?OpenGl.dll?... dann läuft es auch bei euch) So, was kann man nun aber mit Open Gl machen? Na ja: es ist an sich sehr einfach ein Beispiel zu finden... Drückt doch bitte einmal auf Start, wählt nun ?Programme? und startet dieses nette Spielchen, welches sich ?Quake 3 Arena? nennt... Wie? Ihr seit ehrliche Menschen und habt kein Q 3? Nahgut... dann zockt ne runde ?Counter Strike? das ist auch beweiß genug, was man mit Open Gl alles so anstellen kann... nun staunt ihr, oder? Viele werden sich jetzt fragen: kann ich das auch? Die Antwort ist: ?Jein? An sich kann es jeder, aber jetzt noch nicht Nein: lasst uns ehrlich sein: natürlich ist es irgendwie möglich, so was auch zu machen, aber es ist ein langer Weg dorthin und an solchen Spielen haben zig Entwickler schon einiges Zeit gearbeitet. Aber ganz ehrlich: wenn ihr eure Ansprüche etwas zurücksetzt, werdet ihr in diesem Kurs ne Menge lernen... z.B. wie man mit der richtigen Technik in wenigen Minuten ne einigermaßen passable Landschaft gestallten kann, usw. ------------ Teil 2 ---------- Open Gl - Delphi ? Kurs Teil 2: Wie Initialisiert man Open Gl in Delphi Einleitung Ach Leute, ist es schon wieder soweit? Schon wieder 2 Wochen rum? Na ja... dann werde ich wohl müssen... In diesem Kursteil wollen wir also Open Gl in Delphi initialisieren, d.h., dass wir Open Gl klar machen wollen, dass es in unserem Fenster etwas zeichnen kann... mehr nicht! Ich weiß, das dieses für extrem wissbegierige sehr wenig ist, aber ich möchte auch ausreichend genug auf Kleinigkeiten eingehen können, damit nicht wieder so was Unvollständiges wie in meinem Kurztut dabei rauskommt. Leider muss ich auch sagen, das dieser Teil des Kurses der ziemlich Trockenste und Langweiligste wird. An sich ist die Initialisierung eh jedes mal das selbe... für alle andren Teile des Kurses würde es auch reichen, wenn ihr euch einfach das Sample runterladen würdet und es als Grundgerüst für alles andre verwenden würdet. Wer wirklich lust hat und sich nicht entmutigen lässt, der darf ja ruhig auch lesen (aber hinterher nicht entnervt aufgeben!!!) Wie initialisiert man Open Gl Dann wollen wir also... Zunächst haben wir nur ein sehr leeres Projekt vor uns, ganz ohne eigenen Code...
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.DFM} end. Soweit, so gut... das sollte nun zunächst jeder vor sich sehen. Der erste Schritt besteht nun darin, an den Uses ? Teil hinter ?Dialogs? noch die Unit ?Opengl? einzutragen, damit Delphi die nötigen Dinge erst mal parat hat. Nun benötigen wir ein paar Variablen, welche wir in den Privat ? Bereich schreiben. Es handelt sich bei den ersten Zwei um Variablen, welche bei der Erstellung des OGL Kontextes benötig werden. Die dritte ist die Variable für die Farbpalette. Zudem müssen wir schon mal die Prozedur mit Namen ?SetupPixelFormat? hier einragen. Sie wird später gebraucht, da in ihr die meisten Open Gl ? Einstellungen vorgenommen werden. Das Ganze sollte nun so aussehen (Veränderungen sind rot markiert):
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, opengl; type TForm1 = class(TForm) private { Private-Deklarationen } myDC : HDC; myRC : HGLRC; myPalette : HPALETTE; procedure SetupPixelFormat; public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.SetupPixelFormat; begin end; end. So Leute: weiter im Programm! Nun benötigen wir noch ein Paar kleine Dinge: 1) wir legen eine kleine Prozedur Namens ?Render? an (die kann auch anders heißen, aber ich möchte das ganze Normieren, d.h. ich möchte, dass ich nicht immer sagen muss ?ruft nun eure Rendering ? Methode auf?... Ihr wisst schon, was ich meine 2) Wir brauchen die 2 Prozeduren ?Form.create? und ?Form.destroy?. In die erste soll später die eigentliche Initialisierung und die andere Brauchen wir, um den Rendering ? Kontext (das Ding, was Open Gl sagt, wo es zeichnen soll) wieder freizugeben. 3) Und zuletzt: die OnRezise ? Prozedur, damit wir auch ne Anständige Sichtweise bekommen (haben wir dich nicht schon???) So... wenn wir das haben, dann könnten wir uns ja an die ganze Aktion wagen. Ich schreibe euch hier nun mal den ganzen Code rein (mit ?Oncreate?,usw) und erkläre euch dann, was das alles zu Bedeuten hat:
Delphi-Quellcode:
So und nun die Erklärung:
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,OpenGl; type TForm1 = class(TForm) private { Private-Deklarationen } myDC : HDC; myRC : HGLRC; myPalette : HPALETTE; procedure SetupPixelFormat; public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.SetupPixelFormat; begin end; procedure Render; begin end; procedure TForm1.FormCreate(Sender: TObject); begin form1.myDC:= GetDC(Handle); SetupPixelFormat; myRC:= wglCreateContext(myDC); wglMakeCurrent(myDC, myRC); glEnable(GL_DEPTH_TEST); glLoadIdentity; end; procedureTForm1.FormDestroy(Sender:TObject); beginwglmakecurrent(0,0); wgldeletecontext(mydc); releasedc(handle,mydc); end; procedure TForm1.FormResize(Sender: TObject); begin glViewport(0, 0, Width, Height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, Width/Height, 1.0, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); end; end. Ich denke, wir fangen mal mit ?OnCreate? an: Also: ?DC? bedeutet soviel wie Device Context... womit dann auch klar wäre, das in der ersten Zeile von ?oncreate? zunächt erst mal der Device ? Context unseres Hautfensters ausgelesen wird (wer nicht weiß, was das bedeutet: es ist nicht wirklich notwendig das zu wissen... wer noch nicht ewig mit PCs arbeitet muss es auch nicht wissen... die, die schon länger damit arbeiten wissen, was gemeint ist ? ich kann es nämlich nicht wirklich gut erklären) In der nächsten Zeile wird dann unsere Prozedur ?SetupPixelFormat? auf... was die bedeutet, wisst ihr ja bereits: Dort werden wir einige kleine Settings vornehmen. So... weiter im Kontext (im wahrsten sinne des Wortes): Die nächsten beiden Zeilen bewirken zunächst, das aus dem Device Context unseres Fensters ein Open Gl Rendering Context (rc) erzeugt wird und daraufhin aktiviert wird. Die nächste Zeile dürfte dagegen an sich klar sein: Hier aktivieren wir via ?glenable? den Open Gl Tiefentest. Dies bewirkt, das Open Gl immer überprüft, wo in der Tiefe das zu Zeichnende Objekt liegt... ist es zu weit weg, oder von etwas anderem verdeckt, wird es gar nicht erst berechnet. Insbesondere bei großen Szenen ist diese Tiefenüberprüfung also mehr oder weniger maßgeblich für die Performance der Szene... Open Gl erzwingt diesen Modus aber nicht (wäre auch schlecht... es gibt auch Situationen, wo der Tiefentest deaktiviert werden muss... z.B. wenn man mit viel Transparenz arbeitet) Der letzte Befehl ist nicht ganz einfach zu erklären. Dazu muss man über die >Funktionsweise von Open Gl näher bescheid wissen. Und zwar: alle Objekte in Open Gl würden, wenn sie denken könnten und wüssten, wie sie entstehen praktisch wahnsinnig werden: Alle Objekte werden Praktisch über die sogenannte ?Welt-Matrix? (die dem aus dem Film Matrix nicht unähnlich ist) zunächst erstellt, dann gedreht, skaliert und natürlich auch verschoben. Dazu gibt es in Open Gl praktisch einen imaginären Punkt, welcher sagt, an welcher Stelle nun gezeichnet werden soll (besser: um welchen Punkt rum zu gezeichnet werden soll) ?glloadidentity? lädt nun den Ursprung (0,0,0) als diesen Punkt, oder auch gesagt: Es setz die ganze zukünftige Szene zurück. Dies ist zwingend notwendig, denn wir wollen unsere Szene ja nicht irgendwo ins Nirwana zeichnen, sondern wir wollen wissen, wo die Szene ist, damit wir uns diese ansehen können. Im übrigen: es gibt nicht nur diese eine World ? Matrix, sondern es gibt noch viele mehr: eine für Texturen, eine für die Projektionseigenschaften, usw. So... nachdem wir diesen Textbrocken von onCreate hinter uns gelassen haben, machen wir mal was kleineres: wir beschrieben onDestroy: Denn an sich gibt es da nichts zu erklären: alle drei Prozeduren dienen nur dazu, den Rendering ? Kontext wieder frei zu geben, um Open Gl klar zu machen, dass es nun nicht mehr auf unserem Formular zeichnen soll. Hmm... nun fehlt natürlich nur noch onresize... Wie ihr vielleicht wisst, wird onresize aufgerufen, wenn die Größe des Formular geändert wird. An diesem Punkt muss man Open Gl quasi neu konfigurieren, damit nicht alle Objekte unserer Szene total verzerrt gezeichnet werden (ihr könnt ja mal Testweise diesen Code weglassen... ihr dürftet aber kaum glücklich damit werden) An sich sind die Prozeduren hier sehr einfach zu verstehen: Zunächst wird Open Gl klar gemacht, wie die neuen Maße unseres Fensters aussehen... besser: Wir legen den rechteckigen Rahmen fest, in dem gezeichnet werden soll. Dann schalten wir in die Projektionsmatrix damit wir die Darstellungsweise unserer Szene direkt verändern können. Nun setzen wir per glloadidenity diese Matrix komplett zurück (man erinnert sich ) Als nächstes setzen wir die neuen Settings für die Darstellung vor... das übernimmt für uns ?gluperspective?, welches 4 Parameter erwartet: Der erste (bei uns 45) steht für die Gradzahl des Blickwinkels. Hier werden meistens werte zwischen 30 und 45 gewählt, die dem natürlichen Blickwinkel entsprechen. Der nächste steht für das Breiten ? Längen ? Verhältnis, welches dadurch angegeben wird, dass man die Breite durch die Höhe teilt. Die letzen zwei Parameter stehen für den nächsten und den entferntesten sichtbaren Punkt für unsere Kamera. Das heißt: wenn wir auf dem Ursprung steht, und in die z-Richtung sieht, dann ist der nächste Punkt, den man sehen kann einer mit der Z-Koordinate 1 und der entfernteste (der Horizont) wir durch Objekte mit der Z-Koordinate 100 gebildet. Die letzen beiden Funktionen schalten an sich nur noch in den Normalmodus zurück, damit auch wieder normal gezeichnet werden kann. Im übrigen: In dieser Initialisierung verwenden wir die perspektivische Darstellungsweise verwendet, welche die Realitätsnahe ist. Als Alternative gibt es noch die Orthographische, welche hauptsächlich in CAD ? Programmen verwendet wird. Allerdings werden hier alle Objekte mit ihrer Originalgröße dargestellt... unabhängig vor ihrer Entfernung zum Betrachter. So... das war nun aber derbe viel. Ich hoffe, dass alle anderen Teile nicht ganz so theorieastig werden. Aber eine Sache fehlt noch: ?SetupPixelFormat? ist noch sehr mager mit Code bestückt. Wie bereits gesagt: in dieser Prozedur nehmen wir die Einstellungen für Open Gl vor. Ich poste hier einfach mal eine gültige Variante. Ich werde dieses nun nicht ganz so genau erklären, aber ich habe das Wichtigste mit Kommentaren versehen, damit ihr bei bedarf Änderungen problemlos vornehmen könnt (es wäre etwas arg viel, ins Detail einzugehen)
Delphi-Quellcode:
Nun ist es an sich fast vollbracht. Uns fehlen nur noch 2 Dinge: Einen Platz, wo wir ein Objekt rendern können und ein Objekt.
procedure TForm1.SetupPixelFormat;
var hHeap: THandle; nColors, i: Integer; //Anzahl der Farben lpPalette : PLogPalette; //Die Farbpalette byRedMask, byGreenMask, byBlueMask: Byte; //Blau, Grün und Rot nPixelFormat: Integer; pfd: TPixelFormatDescriptor; //Dies ist der "Descriptor"... in ihm werden die Infos // zwischengespeiichert begin FillChar(pfd, SizeOf(pfd), 0); with pfd do begin //wir woollen das Format bearbeiten nSize := sizeof(pfd); // Länge der pfd-Struktur nVersion := 1; // Version dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; // Flags iPixelType:= PFD_TYPE_RGBA; // RGBA Pixel Type cColorBits:= 24; // 24-bit color (Anzahl der Farben) cDepthBits:= 32; // 32-bit depth buffer iLayerType:= PFD_MAIN_PLANE; // Layer Type end; nPixelFormat:= ChoosePixelFormat(myDC, @pfd); //Das Pixel-Format SetPixelFormat(myDC, nPixelFormat, @pfd); // wird übertragen // Farbpalettenoptimierung wenn erforderlich DescribePixelFormat(myDC, nPixelFormat, //alles ab hier ist zwecks einstellungen nicht //mehr wichtig, sondern schlicht und einfach nur noch notwendig... ;-) sizeof(TPixelFormatDescriptor),pfd); if ((pfd.dwFlags and PFD_NEED_PALETTE) <> 0) then begin nColors := 1 shl pfd.cColorBits; hHeap := GetProcessHeap; lpPalette:= HeapAlloc(hHeap,0,sizeof(TLogPalette)+(nColors*sizeof(TPaletteEntry))); lpPalette^.palVersion := $300; lpPalette^.palNumEntries := nColors; byRedMask := (1 shl pfd.cRedBits) - 1; byGreenMask:= (1 shl pfd.cGreenBits) - 1; byBlueMask := (1 shl pfd.cBlueBits) - 1; for i := 0 to nColors - 1 do begin lpPalette^.palPalEntry[i].peRed := (((i shr pfd.cRedShift) and byRedMask) *255)DIV byRedMask; lpPalette^.palPalEntry[i].peGreen:= (((i shr pfd.cGreenShift)and byGreenMask)*255)DIV byGreenMask; lpPalette^.palPalEntry[i].peBlue := (((i shr pfd.cBlueShift) and byBlueMask) *255)DIV byBlueMask; lpPalette^.palPalEntry[i].peFlags:= 0; end; myPalette:= CreatePalette(lpPalette^); HeapFree(hHeap, 0, lpPalette); if (myPalette <> 0) then begin SelectPalette(myDC, myPalette, False); RealizePalette(myDC); end; end; Um ersteres werden wir uns nun noch kümmer: Legt (direkt unter SetupPixelFormat)ne Prozedur ?Render? an, welche nur drei Befehle beinhalten sollte:
Delphi-Quellcode:
Der erste Befehl bewirkt, dass unsere ganze Szene, welcher sich noch im Puffer befindet, gelöscht wird, damit es nicht zu Überschneidungen und Verschmierungen kommt. Wer mal sehen will, was es heißt, diesen Befehl nicht auszuführen, der sollte mal ne Runde CS zocken und dann als Spectator durch eine Wand laufen... alles verwischt und verschmiert total.
Prozedure render;
begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glLoadIdentity; SwapBuffers(form1.myDC); end; Der zweite Befehl sollte schon bekannt sein: er setzt die World ? Matrix wieder zurück, damit die Szene auch wieder am richtigen Ort mit richtiger Rotation und Skalierungen gezeichnet wird. Der letzte Befehl bewirkt nun noch, das Open Gl die Szene auch wirklich darstellt. Nun müssen wir nur noch die Render ? Prozedur irgendwie aufrufen. Unter der VCL bietet sich dafür der Timer an. Wir erstellen nun also einen normalen Timer, dessen Intervall wir auf 1 einstellen und lasen diesen unsere Render ? Prozedur aufrufen.
Delphi-Quellcode:
Wenn ihr die Delphi X ? Komponenten habt, solltet ihr den DX ? Timer verwenden. Dies hat folgende Gründe:
procedure TForm1.Timer1Timer(Sender: TObject);
begin render; end; Wenn ihr den normalen Timer auf eins stellt, schafft er dennoch nichts schnelleres, als etwa 50. Das bedeutet, dass wir maximal 20 fps erreichen können. Der DX ? Timer hingegen ist viel korrekter. Mit ihm erreicht man normalerweise ein Maximum von ca. 80 ? 160 FPS. Diese schon recht dollen FPS ? Zahlen wird man zwar insbesondere mit großen szenen fast nie erreichen, aber man schafft fast immer mehr, als mit dem normalen Timer. So... nun haben wir Open Gl schon beinahe komplett lauffähig. Nun fehlt nur noch unseres Objekt... aber das behandeln wir im nächsten Kapitel. Ich hoffe, dieses Kapitel hat euch nicht entmutigt, denn die Programmierung von 3d ? Szenen mit Open Gl ist sehr einfach... bloß die Initialisierung ist eine etwas umfangreiche und harkeilige Sache. Wer in diesem Kapitel nicht mitgekommen ist, den kann ich beruhigen: das nächste wird viel einfacher. Wenn ihr wollt, könnt ihr euch auch einfach die ganze Initialisierung saugen... auf der Indexseite zu diesem Kurs gibts alle Samples... ------------ Teil 3 ---------- Open Gl - Delphi ? Kurs Teil 3: Objekte und die World Matrix Einleitung *Mit den Fingern Knack* so... nun ist es also schon wieder soweit: der dritte Teil meines Delphi ? Open Gl ? Kurses steht an. Diesmal (Mitlehrerweile schon 4 Wochen nach dem ersten Teil) wollen wir endlich mal was zeichnen! Ich hoffe, dieser Teil wird nicht ganz so Theorielastig, wie der Letzte. Aber ich kann euch beruhigen: wahrscheinlich wird dieser Teil ein großer Spaß... auch wenn ich leider doch mit ein wenig Theorie anfangen muss, aber wenigstens dürfte diesmal am ende wenigstens was zu sehen sein (wenn man das Sample des letzen Teiles startet, hat man noch einen schwarzen Bildschirm). Also los! Die Open Gl Basics So Leute nun wird es Zeit, euch über die Basics von Open Gl aufzuklären. Also wie gesagt: Wenn ihr bislang eure Szene startet, so werdet ihr bemerken, dass es sich nur um einen schwarzen Bildschirm handelt. In diesen wollen wir nun was ?reinrendern?. Bloß wohin genau? Gibt es irgendwelche Koordinaten? Ja, es gibt welche! Es handelt sich dabei um die Koordinaten der World Matrix oder auch Welt Koordinaten. Viele von euch haben ja schon mal in Mathe ein Koordinatensystem gesehen, und unseres ist diesem nicht unähnlich. In der Mitte des Ganzen ist der Ursprung, also der Punkt, bei welchem alle Koordinaten den wert null haben. Neben der X ? Achse, welche links negativ ist und rechts positiv, und der Y ? Achse, die unten negativ und oben positiv ist, gibt es in Open Gl auch noch die Z ? Achse. Die verläuft aber nicht, wie viele denken, von hinten positiv nach vorne negativ, sondern sie wird nach hinten hin negativ!!! Dies ist insbesondere für Direkt X ? Freaks sehr schwer am Anfang, da es dort genau anders herum ist. Man sollte also darauf aufpassen, wenn man sich keine riesigen Fehler einfangen will. Ich habe dazu mal eine Kleine Grafik gemalt: @alle, die dieses Tut auf der Delphipraxis-Site lesen: hier war im Original ein Bild So... das hätten wir schon mal. Aber wo genau sind wir nun? Tja, das ist leicht beantwortet: wir stehen dort, wo alles begann ? auf dem Ursprung. Und was können wir alles sehen? Das hatten wir im letzen Kapitel doch schon mal: alles, was nicht weiter als 100 Einheiten von uns weg ist und nicht gerade außerhalb unseres 45° Winkels liegt... also eine Ganze Menge. Aber wir müssen eines Beachten: dank unserer Einstellungen darf das Objekt nicht näher als 1 sein, sonst sehen wir gar nichts!!! Ich will was Zeichnen!!! Ja ja kommt ja schon... Also, wie malt man denn nun überhaupt was? Auch da gibt es 2 wichtige Basics: 1) Alle Objekte werden zwischen glbegin( ) und glend; gerendert. In der Klammer von glbegin gibt man dazu den Objekttyp an. Z.B. ob es sich um Punkte, Linien, Dreiecke oder Quadrate handeln soll. 2) Alle Objekte werden durch Punkte gezeichnet. Der befehl für einen Punkt heißt glvertex. Glvertex kann aber verschieden viele Parameter haben. So gibt es eine Variante glvertex2f und eine glvertex3f. Der Unterschied ist klar: glvertex2f verlangt 2 Floats als Parameter (x und y Koordinate)... glvertex3f hingegen 3 (x, y und z Koordianten) Und was sagt uns das? Tja... man kann mit Open Gl nicht nur 3d, sondern auch 2d zeichnen, was aber nicht unbedingt Sinn der Sache ist. Ich habe mir überlegt, dass wir folgende Szene erreichen wollen: @alle, die dieses Tut auf der Delphipraxis-Site lesen: hier war im Original ein Bild Was brauchen wir denn zunächst dazu? An sich benötigen wir zunächst mal ein Quadrat. Und wie zeichnen wir das? Wie oben bereits gesagt mit 4 Punkten. Wir haben ja bereits unsere Render ? Prozedur. In dieser habe ich beabsichtigt eine keine Lücke gelassen. In diese kommt nun unserer Code. Wir wollen mal sehen, was passiert, wenn wird diesen dort eintippen:
Delphi-Quellcode:
So, das will ich erst mal erläutern:
Glbegin(gl_quads); //wir wollen ein Viereck zeichnen
glVertex3f( 1 , 1, -2); glVertex3f( -1 , 1, -2); glVertex3f( -1 , -1, -2); glVertex3f( 1 , -1, -2); glend; Also mit glbegin(gl_quads); beginnen wir, Vierecke zu zeichnen. Danach folgen die Vier Eckpunkte und zuletzt das Abschleißende glend. Aber was ist das, wenn wir das nun starten? Die Szene ist urplötzlich ganz weiß!!! Wie kann das denn nun? Die Erklärung für dieses Phänomen ist sehr einfach: Der nächste Punkt, den wir sehen können, hat die Koordinaten (0,0,-1) das heißt: wir sind sehr nahe drauf auf unserer Kamera! Unser Objekt ist schlich zu nahe, um ins Bild zu passen! Was tun wir folglich dagegen? Wir zeichnen es etwas weiter weg. Mit diesem Code zeichnet man es z.b. schon mal 4 Einheiten weiter nach hinten, als bisher. Das hilft schon sehr.
Delphi-Quellcode:
Das sieht dann schon eher, wie das gewünschte Viereck aus:
Glbegin(gl_quads); //wir wollen ein Viereck zeichnen
glVertex3f( 1 , 1, -6); glVertex3f( -1 , 1, -6); glVertex3f( -1 , -1, -6); glVertex3f( 1 , -1, -6); glend; @alle, die dieses Tut auf der Delphipraxis-Site lesen: hier war im Original ein Bild Aber irgendwie sieht das noch sehr eintönig aus. Aber das ändern wir nun. Ich sehe... Farben So... wie bekommen wir nun also etwas Farbe in unseres Viereck? Also, falls nun schon irgendwer auf den Gedanken gekommen ist, jedes Pixel für Pixel einfach nachzuzeichnen, wird er gelyncht! Das geht viel einfacher! Man ist es ja bereits gewohnt, das sich Farbe in PCs aus rot, grün und blau zusammensetzt. Und so läuft das auch hier! Mit dem Befehl glcolor3f, welcher drei Parameter verlangt (sieht an ja auch an dem ?3f?) kann man nun eine Farbe setzen. Aber es gibt eines zu beachten: Die Farbwerte werden zwischen 0 und 1, also als Float angegeben! Wer nun also gerne seine HTML ? Farben verwenden wollte, der sollte alle Farbwerte schleunigst durch 256 teilen, damit das auch hinhaut! Also: wir schreiben nun vor dem Zeichnen unseres Vierecks ein glcolor3f, mit dem wir eine rote Farbe erzeugen wollen:
Delphi-Quellcode:
Dann sieht das Ganze schon mal so aus:
glcolor3f(1,0,0) //rote Farbe
Glbegin(gl_quads); //wir wollen ein Viereck zeichnen glVertex3f( 1 , 1, -6); glVertex3f( -1 , 1, -6); glVertex3f( -1 , -1, -6); glVertex3f( 1 , -1, -6); glend; @alle, die dieses Tut auf der Delphipraxis-Site lesen: hier war im Original ein Bild Aber wo bekommen wir nun diese schönen Farbverläufe her? Das ist an sich ganz einfach: Man kann für jeden Punkt eine einzelne Farbe angeben. Da ja alle punkte dank unseres glbegin(gl_quads) zu einem Viereck verbunden wird, werden die Farbverläufe einfach automatisch berechnet! Dies kann manchmal sehr nützlich sein. Daher brauchen wir unseren Quadratcode nur so umschreiben: Glbegin(gl_quads); //wir wollen ein Viereck zeichnen glcolor3f(1,0,0) //rote Farbe glVertex3f( 1 , 1, -6); glcolor3f(0,1,0) //grüne Farbe glVertex3f( -1 , 1, -6); glcolor3f(1,1,0) //gelbe Farbe glVertex3f( -1 , -1, -6); glcolor3f(0,0,1) //blaue Farbe glVertex3f( 1 , -1, -6);glend; Und schon haben wir unseren Farbverlauf! Vom Schieben, Drehen und Skalieren An sich ist Open Gl ja richtig brutal und kriminell! Hier werden einige Autos und andere Objekte durch die Gegend geschoben, woanders werden Dinge komplett verdreht und irgendwo skaliert man aus einer Mücke einen Elefanten! Einfach kriminell! Aber so schlimm ist es nun auch wieder nicht. Was wäre das für eine Welt, ohne Animationen? Wäre nicht gerade lustig, würde ich sagen... Na ja, was soll also das Geschwafel? Ich möchte euch nun beibringen, wie das eben genannte also funktioniert. Ich fange mit dem Verschieben an: Zum Verschieben reicht in Open Gl ein einziger Befehl! Nämlich gltranslate. Dieser Befehl verlangt - wie sollte es auch anders - 3 Parameter. Diese sagen ganz easy aus, wohin verschoben werden soll. Wenn ich also vor unserem Viereck ?gltranslate(0,1,-2)? aufrufe, dann verschieben wir es um ca. zwei Weltkoordinaten nach hinten und um eine nach oben. Das heißt also auch, dass wir unser viel zu nahes Anfangsquadrat hätten lassen können und einfach ?gltranslate(0,0,-4)? davor hätten aufrufen können, womit ich euch aber erst nicht belasten wollte. Nun werde ich erst mal zum drehen kommen (keine Sorge, ich mache noch ein Sample am Ende mit allen befehlen zusammen... versprochen) Es dreht sich Das Drehen geht an sich genauso einfach von der Hand, wie das Verschieben. Zum Drehen braucht man nämlich nur den Befehl ?glrotate?. Dieser Befehl verlangt insgesamt 4 Parameter. Der erste ist der Winkel in Grad. Die andren Drei stehen wieder für eine X,Y und Z ? Koordinate, welche die Achse beschrieben soll, um die rotiert wird. Wenn man also ?glrotate(45, 0, 1, 0)? aufruft, dann dreht sich alles nachfolgende um 45° um die Y ? Achse. Was man nun zuerst tut (Drehen oder Verschieben) ist jedem selber überlassen, aber es hat sehr verschiedene Auswirkungen! Das liegt daher, das immer um den Punkt gedreht wird, um den eben ?translatet? wurde! Spielt doch einfach etwas damit (und mit den Parametern) rum. Ich werdet den Bogen schnell raushaben! Na denn: Skalieren So, womit wir auch schon beim skalieren wären. Lasst es uns kurz machen: zum Skalieren braucht man nur den Befehl ?glscale?, der insgesamt drei Parameterchen haben möchte. Die erste gibt die Skalierung der X ? Richtung an, womit auch klar wäre, das die beiden anderen für Y und Z zuständig sind. Wenn man nun also ein Objekt gleichmäßig vergrößern oder verkleinern will, so muss man einfach alle Werte gleichmäßig erhöhen oder erniedrigen. Eine Sache muss aber noch beachtet werden: es handelt sich bei den werten um Multiplikatoren und nicht um Summanden!!! Einige Leute denken: ?Wenn du null als Parameter angibt, dann verändert sich Größe null? und wundern sich dann, wenn urplötzlich nichts mehr zu sehen ist. Also: wenn ihr die Größe eine Koordinate nicht ändern wollt, dann solltet ihr 1 angeben, wollt ihr sie verdoppelt, so gebet 2 an und wollt ihr sie halbieren, so hat der Parameter 0.5 zu heißen! Ach ja noch was: Ein Objekt wird immer vom Ursprung aus skaliert. Damit macht es dann doch einen Unterschied, ob wir ein Objekt gleich an die richtige stelle schieben, oder aber sie am Ursprung erstellt und dann verschiebt..... Und nun: Das Sample So, nun möchte ich also mit euch ein kleines Sample bauen. Das ganze soll so aussehen: Wir verwenden unseres Quadrat von vorhin und versuchen, dieses 1) von der Größe her pulsieren zu lassen 2) langsam immer von oben nach unten zu bewegen 3) es ständig um die eigene Z ? Achse rotieren so lassen Damit wäre unser Auftrag klar. Zunächst benötigen wir insgesamt fünf neue globale Variablen:
Delphi-Quellcode:
So... damit hätten wir schon mal die wichtigsten Variablen beisammen. Nun müssen wir diesen nur noch werte zuweisen. Dazu habe ich mir gedacht, nehmen wir uns einen neuen Timer, den wir auf etwa 50 stellen. Dort müssen wir dann die werte zuweisen:
var Form1: TForm1;
scale : single = 1; //Für die Skalierung rotation : integer = 0; //Zahl in °, um die gedreht wird move : single = 0; //Größe der Bewegung scaledir : boolean; //Richtung der Skalierung (größer / kleiner) movedir : boolean; //Richtung der Bewegung (rauf / runter)
Delphi-Quellcode:
procedure TForm1.Timer2Timer(Sender: TObject);
begin if scale > 1.2 then //ist dei höchste stufe der Skalierung erreicht? begin scaledir := false; //Ja : Skalierung umkehren end; if scale < 0.8 then //ist dei niedrigste Stufe der Skalierung erreicht? begin scaledir := true; //Ja : Skalierung umkehren end; if scaledir = true then //Soll die scalierung größer werden? begin scale := scale + 0.02; //JA: Scale erhöhen end else begin scale := scale - 0.02; //Nein: Scale ernidrigen end; inc(rotation); //Die rotation in "°" erhöhen if move > 1 then //ist der höchste Punkt der Bewegung erreicht? begin movedir := false; //Ja : Bewegung umkehren end; if move < -1 then //ist der niedrigste Punkt der Bewegung erreicht? begin movedir := true; //Ja : Bewegung umkehren end; if movedir = true then //Soll die Bewegung nach oben gehn? begin move := move + 0.02; //JA: Move erhöhen end else begin move := move - 0.02; //Nein: Move ernidrigen end; end; Ich denke mal, dass ich diesen Quelltext nicht unbedingt näher erklären muss. Er erklärt sich ja praktisch von selbst: zunächst wird die Skalierung, dann die Rotation und zuletzt die Bewegung bearbeitet. Wenn man das ganze nun aber startet, dann sieht man nichts! Besser: es bewegt sich nichts! Das ist aber auch nicht schwer zu erraten, wieso. Ganz einfach: wir verarbeiten die neuen Werte noch nicht. Dazu müssen wir noch unsere Render ? Prozedur noch etwas abändern:
Delphi-Quellcode:
Das wäre auch schon alles! Wenn wir nun das ganze starten dürften wir ein quietschbuntes Viereck sehen, welches gegen jedes Gesetz der Physik verstößt. Aber das ist an sich ja halb so schlimm: es war ja quasi Sinn der Sache, euch mal irgendwie alles zusammen zu zeigen. Wer dort noch nicht ganz durchgestiegen ist: saugt euch das Sample und spielt etwas mit den Parametern rum: ihr werdet dabei ne Menge lernen!
procedure render;
begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glLoadIdentity; gltranslate(0,move,0); //wir bewegen alles etwas nach oben oder unten glscale(scale,scale,1); //Nun skalieren wir die Szene glrotate(rotation,0,0,1); //Und ab in die Drehung um die Z-Achse ;-) glBegin(GL_Quads); glcolor3f(1,0,0); glVertex3f( 1 , 1, -6); glcolor3f(0,1,0); glVertex3f( -1 , 1, -6); glcolor3f(1,1,0); glVertex3f( -1 , -1, -6); glcolor3f(0,0,1); glVertex3f( 1 , -1, -6); glEnd(); gltranslate(0,0,-3); glcolor3f(0,0,1); SwapBuffers(form1.myDC); end; Nachwort So, das war?s auch ?schon? mit Teil 3 meines Open Gl Kurses. Ich hoffe, diese Acht Seiten waren etwas Unterhaltsamer, als die sieben Seiten aus dem 2. Teil und ich hoffe, dass ich euch in zwei Wochen wieder begrüßen darf, wenn wir zum Thema ?Zeichenmethoden? kommen. Dort werde ich euch beibringen, wie man Punkte, Linien, Dreiecke, Rechtecke und Polygone in den verschiedensten Zeichenstärken, usw. Macht. Zudem machen wir noch einen kleinen Abstecher in die Welt der 3d ? Objekte (in der wir ab dann auch bleiben werden). Ich werde euch also zeigen, wie man Pyramiden, Würfel und Kugeln auf den Screen bekommt. Ich hoffe, wir sehen uns wieder. ------------ Weiteres ---------- Der Kurs geht natürlich weiter, das Problem ist blos, dass es von noch nicht allen Teilen online-Versionen gibt und ich damit von noch nicht allen alle Bilder hochgeladen habe... Leider arbeite ich in fast allen Kursteilen ab Teil 4 mit sehr vielen Bildern und deshalb wären diese Parts recht unverständlich ohne... Naja, damit ihr wisst, was euch erwartet hier ne Liste alle Teile: Teil 1: Was ist Open Gl Teil 2: Open GL Initialisieren Teil 3: Das erste Objekt und die World Matrix Teil 4: Zeichenmethoden Teil 5: Texturen Teil 6: Blending Teil 7: Lichter mit Blending Teil 8: Kamerabewegung Und hier der Direktlink zur Kurs-Seite: http://www.dcw-group.net/index.php?m.../oglkurs/index Und damit ihr mir auch glaubt, dass sich das ganze Lohnt, gibts hier noch n kleines Bild (Teil 8): EDIT SAKURA: Schade nur, dass das Bild durch Username/Passwort zugriffsgeschützt ist und wir es nicht sehen können Cu Mr_T [edit=sakura] Link auf geschütztes Bild entfernt. Mfg, sakura[/edit]
Mein neuer, 13 Teiliger Open GL - Kurs (Samples in Delphi):
www.dcw-group.net Neu! Ein großer Teil der Demos nach Kylix übersetzt! Neu! Teil 2b: Initialisierung von OpenGL unter Kylix ist fertig! |
Delphi 2005 Personal |
#2
So, nun gibts nach langer Zeit mal wieder ein kleines Update. Und zwar kommt hier eine kleine Ergenzung zum 2. Teil (Praktisch Teil 2b), bei welchem nun entlich die Initialisierung unter Kylix abgehandelt wird. Viel Spaß mit de, Kursteil (wie immer: Original-Text von meiner HP)
------------ Teil 2b ---------- Open Gl - Delphi/Kylix - Kurs Teil 2b: Wie Initialisiert man Open Gl unter Kylix(3) Einleitung Hi Leute! So, nachdem der Kurs nun schon ganze 13 Teile stark ist, kommt nun endlich ein Kursteil, mit dem sicherlich kaum einer Gerechnet hat: Teil 2b: Initialisieren von Open Gl unter Kylix! Es war ein wirklich langer weg hier her, denn das Umsetzen von Teilen des Kurses nach Kylix war schon vor einer halben Ewigkeit geplant, konnte aber leider nicht umgesetzt werden, weil trotzt Crossplatform – Libary (opengl12.pas) die Initialisierung immer wieder fehlschlug. Nun aber endlich ist es gelungen Open Gl unter Kylix zum laufen zu bekommen und das nicht nur mit der OpenGl12.pas, sondern auch mit der neusten Ausgabe der Opengl1.5-Unit der DGL (dglopengl.pas). Ein großer Dank geht denn nochmals von mir hier aus an DelphiC aus dem DGL-Team, der dieses Möglich gemacht hat. Von ihm stammen auch viele Teile vom Quelltext aus diesem Kursteil. Bevor wir anfangen möchte ich noch ein paar Voraussetzungen für das Entwickeln von Open Gl – Anwendungen unter Linux hier aufführen: Das wohl wichtigste ist zunächst mal eine funktionierende 3D – Unterstützung, d.h. ein geeigneter Treiber für die Grafikkarte. NVidia macht es hier den meisten Leuten mit ihrem Installer ziemlich einfach: RPM installieren und los geht’s (meistens). Bei ATI ist die Sache noch recht kompliziert (aber nicht unmöglich), evtl. auch, weil ATI momentan an sich nur Treiber für FireGl-Karten rausgibt, die aber auch mit allen anderen Radeon-Karten der 8xxx und 9xxx – Reihe laufen. Weiterhin wichtig ist natürlich noch Kylix. Absolut ausreichend für unsere zwecke ist auf jeden Fall mal Kylix 3 Open Edition ... zumindest für unsere Demos reicht das vollkommen. Man kann es kostenlos auf der Borland – HP runterladen. Ich selbst habe das ganze hier auf einem Athlon XP 2600+, einer Radeon 9600 Pro und unter Fedora Core 1 (Kernel 2.4.x, XFree 4.3.X, KDE 3) entwickelt. Los geht’s! So, genug geschwafelt, ran ans Werk! Das erste was wir in unserer frisch erzeugten Kylixanwendung machen müssen (solltet ihr keine lehre vor euch finden, denn erzeugt eine!) ist, ein Panel auf das Form zu ziehen. Dieses müssen wir leider machen, weil unter Kylix man aus irgendeinem mir nicht erdenklichen Grunde nicht direkt aufs Form, sondern nur auf Panels rendern kann. Nur damit Klarheit besteht: ich nenne dieses Panel immer „render_panel“ .... nur damit ihr wisst, was abgeht. So, nachdem das Panel da ist, brauchen wir erstmal noch einen Timer. Dieser soll für uns den Taktgeber spielen (Timer auf „1“ setzen). Zunächst hatte ich noch gehofft, evtl. das Onidle- Event verwenden zu können, dies ging aber nicht, da es unter Linux offensichtlich anders gehandhabt wird als unter Windows und damit selbst bei Standszene die Framerates stark schwanke. So, damit haben wir die CLX-Arbeiten (also den visuellen Teil) abgeschlossen. Nun müssen wir erstmal unsere Open Gl-Unit und die nötige Hilfsunit, welche die GLXFunktionen kapselt einbinden. (GLX ist etwas das, was für die Windowsler WGL ist ... also eine Hilfe, Open Gl auf den Schirm zu bringen): uses .... , dglGLX, dglOpenGl; Als nächstes brauchen wir nun ein paar Variablen, welche wie unter Windows als private Eigenschaft der Form deklariert werden und alle Eigenschaften bezüglich dem Render- Context des Forms beinhalten:
Delphi-Quellcode:
Nun kann es richtig losgehen!
private
{ Private-Deklarationen } OpenGlInitialized : Boolean; dpy : PDisplay; cx : ^integer; vi : PXVisualInfo; glwin : XID; public { Public-Deklarationen } end; ... Nun kommt nämlich das Grauen der Windows-Benutzer dran: die OnCreate-Funktion! Diese bearbeiten wir nun also:
Delphi-Quellcode:
Nanu? Was soll das denn werden? Ist das alles?
procedure TForm1.FormCreate(Sender: TObject);
begin OpenGlInitialized := false; end; Na ja: unter Kylix läuft halt alles ein wenig anders. Irgendwie scheint es Kylix nicht so gut zu bekommen, wenn man direkt im OnCreate initialisiert. Deshalb verschieben wir dieses auf die OnShow-Prozedur:
Delphi-Quellcode:
So, das war eigentlich schon der größte Teil dieses ganzen Tuts. Nachdem wir das geschafft
procedure TForm1.FormShow(Sender: TObject);
var Screen : Integer; Attributes : TAttributes; begin if not OpenGlInitialized then //Noch nicht initialisiert? Also los: begin try //Sicher ist sicher.... InitOpengl; //OpenGl Laden ReadExtensions; //Die Extentions laden ReadImplementationProperties; dpy := XOpenDisplay(#0); //Ein neues Dispaly zum Rendern öffnen Screen := XDefaultScreen(dpy); //Dieses Display verwenden Attributes:= GetAttributes(); //Hier können Attribute an //OGl übergeben werden ... bleibt die //Klammer lehr, denn werden die Standart //Attribute genommen vi := glXChooseVisual(dpy, Screen, @attributes[0]); //Unseren Screen nemen cx := glXCreateContext(dpy, vi, nil, true); //Den OpenGl-Kontext erzeugen glwin := QWidget_winId(render_panel.Handle); //Entgültig unser Panel als //Renderpanel festlegen if not glXMakeCurrent(dpy, glwin, cx) then //Den Renderkontext aktivieren begin WriteLn('OpenGl Initialisierung schlug fehl!'); Exit; end; glShadeModel(GL_SMOOTH); glClearColor(0.3, 0.4, 0.6, 1.0); //Eine etwas nettere Hintergrundfarbe glEnable(GL_DEPTH_TEST); //Tiefentest einschalten glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); FormResize(nil); glLoadIdentity; Caption := Caption + ' @ ' + glGetString(GL_RENDERER); //Hiermit wird der aktuelle Renderer (Radeon, Geforce //oder MESA-Software ausgegeben OpenGlInitialized := true; except WriteLn('OpenGl Initialisierung schlug fehl!') end end; end; haben müssen wir an sich nur noch ein paar Kleinigkeiten erledigen. So muss natürlich noch die altbekannte OnDestroy-Prozedur her, welche ja den OpenGl- Kontext wieder schließt:
Delphi-Quellcode:
Und was natürlich auch noch fehlt ist die Onresize-Prozedur (kennt man ja alles aus Teil
procedure TForm1.FormDestroy(Sender: TObject);
begin if dpy <> nil then begin glXMakeCurrent(dpy,0,0); if cx <> nil then glXDestroyContext(dpy,cx); XCloseDisplay(dpy); end; end; 2(a)):
Delphi-Quellcode:
Nun sind es nur noch zwei kleine Schritte zu vollständigen OpenGl-Initalisierung unter Kylix.
procedure TForm1.FormResize(Sender: TObject);
var Width, Height : Integer; begin Width := render_panel.Width; Height := render_panel.Height; glViewport(0, 0, Width, Height); // Setzt den Viewport fr das OpenGL Fenster glMatrixMode(GL_PROJECTION); // Matrix Mode auf Projection setzen glLoadIdentity(); // Reset View gluPerspective(45.0, Width/Height, 1, 100.0); // Perspektive den neuen Man anpassen. glMatrixMode(GL_MODELVIEW); // Zurck zur Modelview Matrix glLoadIdentity(); end; Zunächst muss nämlich noch das Timer-Event eingefügt werden, da wir sonst ja keinen Taktgeber für die Render-Prozedur haben:
Delphi-Quellcode:
Und zu guter letzt muss noch die Render-Prozedur selbst her (man sollte sie im Quelltext über
procedure TForm1.Timer1Timer(Sender: TObject);
begin if OpenGlInitialized then begin render; end; end; das Timer-Event schreiben, da ansonsten der Timer evtl. die Render-Prozedur nicht finden kann:
Delphi-Quellcode:
Hier kommt nun die erste (und letzte kleine Überaschung). Leider funktioniert der alte
procedure render;
begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); //Farb und Tiefenpuffer lschen glLoadIdentity; glXSwapBuffers(form1.dpy, form1.glwin); end; Swapbuffers-Befehl nämlich unter Linux nicht, was aber nicht Tragisch ist, das die GLXFunktionen einen passenden Ersatz parat haben. So, damit ist unsere Initialisierung unter Kylix auch schon fertig und wir können fröhlich auch unter Linux in die Welt von OGL einsteigen. Nachwort So, und schon ist es vollbracht! Ich hoffe es hat euch allen soviel Spaß gemacht wie mir und wird euch soviel Spaß wie mir machen, endlich auch unter Linux mit OGl runspielen zu können. Zumindest solltet ihr mit diesem Kursteil die nötigen Voraussetzungen haben, auch wenn ich zugeben muss, dass ich mich hier sehr kurz gehalten habe (dieser Kursteil ist in 4 Tagen und das während der Facharbeits-Zeit entstanden ... mehr Zeit war leider nicht...). Ein kleines Versprechen habe ich noch: Demnächst gibt es für Teil 5 noch ein kleines Anhängsel, welches meine selbst geschriebene Texturen-Unit näher erklärt. Bis dahin könnt ihr euch ja aber schon mal die Demo zu Teil 5 ansehen... normalerweise sollte es echt nicht schwer sein zu erfassen, wie man unter Linux mit dieser Unit Texturen lädt, besonders weil ich mir viel Mühe gemacht habe die Bedienung einfach zu gestalten. Also hoffe ich, dass ihr noch viel Spaß mit OpenGL unter Linux habenwerdet und das ihr auch nächstes Mal wieder reinschaut. Eurer Mr_T |
Zitat |
Delphi 7 Enterprise |
#3
Zunächst mal ein riesiges DANKÖSCHÖÖÖÖN!!!! Ich habe just vor 3 Tagen entschieden, micht nun endlich mal der 3D-Welt zu stellen, und entschied mich für OGl. Dann fand ich deine Tuts, und habe doch tatsächlich einigermaßen verstanden, worum es geht! Ein gutes deutsches Tut zu finden ist schier unmöglih, und dann auch noch in Delphi. Bist z.Zt. mein ganz persönlicher Held (und das ohne Ironie!)
Dann komme ich auch gleich mal mit einer Frage um die Ecke: Habe es nun geschafft, es so zu basteln, dass man sich in der Szene wie in üblichen Ego-Shootern zu bewegen (fly-mode), also mit Mouse-Look und W,S,A,D als "Pfeiltasten". Dann wollte ich zu meinen Würfeln in der Szene ganz gerne ein Licht. Okay, kein Problem, Licht rein, Parameter setzten und glücklich sein. Aber nicht lange . Ich war der festen Überzeugung ein stationäres Licht eingebaut zu haben, aber wenn ich mich durch die Szene bewege, so bewegt sich das Licht in unbestimmter Weise mit (unbestimmt deswegen, weil es kaum nachvollziebar ist, wie es sich nun WIRKLICH bewegt). Das merkt man aber sehr deutlich, da sich die Highlights mit der Kamerabewegung ändern, obwohl die im Gegensatz zu einer Spiegelung ja in erster Linie nix mit der Kameraposition zu tun haben (sollten). Mal ein Stückchen Code:
Delphi-Quellcode:
Habe schon die wildesten Variationen durch. Aber nix brachte wirklich Erfolg. Was kann ich tun? (Lightmaps, wie in deinem Tut angesprochen, sind für meinen Einsatz etwas "overkill", und Texturen wollte ich erst mal zurückstellen, bis ich den Kram mit der Geometrie im Griff hab.)
procedure TForm1.DrawScene;
var i,m: Integer; const light_position : array[0..3] of GlFloat = (0.0, 0.0, 0.0, 1.0); begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glLoadIdentity; CheckKeys; // Die diversen Tastendrücke auswerten glRotate(RotateY,1,0,0); glRotate(RotateX,0,1,0); glTranslate(PosX,PosY,PosZ); glLightfv(GL_LIGHT0, GL_POSITION, @light_position); // diese Licht SOLLTE stationär sein (zu den GLBoxes), da es in der selben Matrix platziert wird... for i := 0 to 9 do for m := 0 to 9 do GLBox[i,m].GLDraw; // ein paar Würfel for i := 0 to 9 do for m := 0 to 9 do GLBox2[i,m].GLDraw; // noch ein paar Würfel SwapBuffers(h_DC); inc(FPS); // Frame-Rate-Counter end; Noch was: Wo ist der Unterschied bei Manipulationen der Matrix in:
Code:
glMatrixMode(GL_PROJECTION);
und glMatrixMode(GL_MODELVIEW); Vielen heissen Dank nochmal, und schonmal , dizzy
Fabian K.
|
Zitat |
Delphi 2005 Personal |
#4
OK, hat ein wenig gedauert bis ich drauf gekommen bin, woran dein Lichtversuch scheitert, aber habts hinbekommen (habe noch nie mit dem Lichtmodel gearbeitet ...)
Und zwar bewegst und drehst du das Licht mit den Objekten mit. Stelle dein "glLightfv(GL_LIGHT0, GL_POSITION, @light_position);" mal vor die rotate und den translate-Befehl und dein Light bleibt da, wo es hingehört. Im übrigen: das mit den Texturen ist wirklich nicht schwer... habe in meinen Tuts zunächst einen nicht geraden einfahcen Weg der Texturierung genommen ... sollte dir das zu schwer sein, denn les dir mal den Texturen-Teil von Teil 9 durch und aus Teil 5 nur den algemeinen Teil ... das kommt deutlich einfacher und ist mithilfe der glbmp-Libary wirklich von jedem Anfänger bewältigbar. Ich hoffe ich konnte dir weiterhelfen |
Zitat |
Delphi 7 Enterprise |
#5
Zitat von Mr_T:
[...] bewegst und drehst du das Licht mit den Objekten mit.
Zitat von Mr_T:
Stelle dein "glLightfv(GL_LIGHT0, GL_POSITION, @light_position);" mal vor die rotate und den translate-Befehl und dein Light bleibt da, wo es hingehört.
Delphi-Quellcode:
Dann bleibt das Licht scheinbar richtig stehen, aber die Kamera bewegt sich falsch. Soll heissen: Sie dreht dann nicht mehr um sich selbst, sondern um einen fixen Punkt in der Szene, nämlich immer um (0/0), egal wie sie positioniert ist. Schwer zu erklären, da es ja eigentlich keine Kamera git, sondern ja lediglich die Szene rumgeschubst wird
glTranslate(PosX,PosY,PosZ);
glLightfv(GL_LIGHT0, GL_POSITION, @light_position); glRotate(RotateY,1,0,0); glRotate(RotateX,0,1,0); for i := 0 to 9 do for m := 0 to 9 do GLBox[i,m].GLDraw; // ein paar Würfel for i := 0 to 9 do for m := 0 to 9 do GLBox2[i,m].GLDraw; // noch ein paar Würfel
Zitat von Mr_T:
Im übrigen: das mit den Texturen ist wirklich nicht schwer... habe in meinen Tuts zunächst einen nicht geraden einfahcen Weg der Texturierung genommen ... sollte dir das zu schwer sein, denn les dir mal den Texturen-Teil von Teil 9 durch und aus Teil 5 nur den algemeinen Teil ... das kommt deutlich einfacher und ist mithilfe der glbmp-Libary wirklich von jedem Anfänger bewältigbar.
Danke dir schon mal! dizzy
Fabian K.
|
Zitat |
Delphi 7 Enterprise |
#6
Kommando zurück!!! Habe mich schämlichster Weise volles Rohr vertan... Das Licht bleibt brav, wo es soll. Die scheinbare Abhängigkeit von der Kamera kam daher, dass ich die Shininess der Materialien angeschaltet hatte, und die ist sehr wohl vom Blickwinkel abhängig!
Wenn ich diese Einstellung weg lasse, dann ist alles gut. Ich geh' dann mal
Fabian K.
|
Zitat |
FreePascal / Lazarus |
#7
@Mr_T
ich habe da auch noch ein kleines problchen: (ch fange gerade mal wieder mit OpenGL an, zum ca 4 mal oder so) ich wollte ein kleines spiel schreiben: skyraodes wo man sich nur nach vorne(die camara soll sich mitbewegen) nach hinten und zu seite bewegen können(die camera soll sich nicht mitbewegen) dazu gabe ich folgenden code:
Delphi-Quellcode:
doch leider bewegen sich die objekte mit bzw. die position verändern sich
begin
fps2 := fps2+1; glMatrixMode(GL_PROJECTION); // In die Projektionsmatrix wechseln glLoadIdentity; // Identitätsmatrix laden glViewPort(0, 50, ClientWidth, ClientHeight); // Viewport an Clientareal des Fensters anpassen gluPerspective(60, ClientWidth/ClientHeight, 1, 128); // Perspective, FOV und Tiefenreichweite setzen glMatrixMode(GL_MODELVIEW); //In die Modelansichtsmatrix wechseln glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Farb- und Tiefenpuffer löschen glLoadIdentity; // Identitätsmatrix laden if mauspos = 1 then rotation := rotation + 1 * timefactor; //Rechtsdrehen if mauspos = 2 then rotation := rotation - 1 * timefactor; //Linksdrehen if GetAsyncKeyState(vk_up) <> 0 then begin // Nach oben Taste gedrückt? Ja: Bewegen ypos := ypos - cos(degtorad(rotation))*0.1*timefactor end; if GetAsyncKeyState(VK_Down) <> 0 then begin // Nach Unten Taste gedrückt? Ja: Bewegen ypos := ypos + cos(degtorad(rotation))*0.1*timefactor end; // glBindTexture(GL_TEXTURE_2D, tex); glRotatef(rotation,0,1,0); //Die entgültige Drehung glTranslatef(0, 0, ypos); //Die entgültige Bewegung glbegin(gl_quads); glvertex3f(-1.4,-0.5,-3); glvertex3f(-0.2, 0.5,-3); glvertex3f( 0.2, 0.5,-3); glvertex3f( 1,-0.5,-3); glend; glTranslatef(0,1,0); glpopmatrix; glbegin(gl_quads); glvertex3f(-1,-0.2,-6); glvertex3f(-0.2, 0.2,-6); glvertex3f( 0.2, 0.2,-6); glvertex3f( 1,-0.2,-6); glend; // Hinteren Puffer nach vorne bringen SwapBuffers(DC); // Windows denken lassen, das wir noch nicht fertig wären Done := False; // Nummer des gezeichneten Frames erhöhen inc(Frames); // FPS aktualisieren if GetTickCount - StartTick >= 500 then begin FPS := Frames/(GetTickCount-StartTick)*1000; Frames := 0; StartTick := GetTickCount end; (ich verwende eine vorlage von delphiGL.com)
Michael Springwald
|
Zitat |
Delphi 12 Athens |
#8
Ein solches Tutorial würde ich mir mal für die 2D-Welt wünschen!
Z.B. zur Anwendung in einem kleinen CAD-Programm. Vor allem solche Dinge wie Zeichenfläche, Zeichenebenen, Grid ein/aus, SnapToGrid, Umschalten von Einheiten (Inch, mil, m, mm, µm...), Zoom, Referenzpunkt umsetzen, Strecken messen, Bildausschnitt, Laden/Speichern/Verwalten von Zeichenobjekten usw... Im kommenden "Der entwickler" soll ja ein Berich zu OpenGL und der CAD/2D-Welt drin sein, aber die kommt erst im Oktober - für mich noch viiiiel zu lang! Grüsse! |
Zitat |
|
#9
2D in OpenGL? Gibts ein Tutorial auf www.delphigl.com
Hoffe das hilft weiter. |
Zitat |
Delphi 12 Athens |
#10
Ja, das kenn ich auch. Schön für 2D-Spiele usw. aber IMHO nix für z.B. CAD! Mir fehlt hier leider der Bezug physikalische Einheit (sprich z.B. Inch) zur virtuellen Einheit (sprich Pixel, Weltkoordinaten, oder was auch immer).
Dito der Rendervorgang! Bei einem Spiel brauch ich idR fps. Bei CAD reicht es aber z.B. wenn nur dann gerendert wird, wenn's sein muss. Sprich z.B. Änderung in der Zeichnung, oder ein Resize der Zeichenfläche. Bei meinen bisherigen Versuchen reichte da Application.OnIdle aus. Die Versuche mit einem eigenen Thread, der das Rendern übernimmt brachten keinerlei Vorteile, sondern verkomplizierten das alles nur. Aber ein Beispiel dazu: Ich will in einem Zoombereich ein Grid (Punkte, keine Linien) darstellen. Sprich auf einer Zeichenfläche von z.B. physikalisch 100x100 Inch z.B. ein Grid von 1 mil. Wenn die Renderroutine sowas über die gesamte phys. Zeichenfläche macht, kannste erstmal Kaffee drinken gehen. Sowas darf nur bei passendem Zoom, im entsprechenden Sichtbereich der Welt geschehen - nie in der gesamten Welt bzw. der gesamten phys. Zeichenfläche! Das sind Probleme zu denen ich gerne mal etwas in einem solchen Tutorial lesen würde... Auch wenn's nicht viele glauben, aber es gibt noch eine Welt jehnseits von Spielen... Grüsse! |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |