AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Tutorials Delphi OpenGl-Kurs
Tutorial durchsuchen
Ansicht
Themen-Optionen

OpenGl-Kurs

Ein Tutorial von Mr_T · begonnen am 2. Jun 2003 · letzter Beitrag vom 21. Apr 2005
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von Mr_T
Mr_T
Registriert seit: 7. Jun 2002
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:
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.
So und nun die Erklärung:

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:
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;
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.
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:
Prozedure render;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glLoadIdentity;

SwapBuffers(form1.myDC);
end;
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.
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:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
render;
end;
Wenn ihr die Delphi X ? Komponenten habt, solltet ihr den DX ? Timer verwenden. Dies hat folgende Gründe:
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:
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;
So, das will ich erst mal erläutern:
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:
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;
Das sieht dann schon eher, wie das gewünschte Viereck aus:

@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:
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;
Dann sieht das Ganze schon mal so aus:

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

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:
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;
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!

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!
 
Benutzerbild von Mr_T
Mr_T

 
Delphi 2005 Personal
 
#2
  Alt 7. Mär 2004, 15:38
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:
  private
    { Private-Deklarationen }
    OpenGlInitialized : Boolean;
    dpy : PDisplay;
    cx : ^integer;
    vi : PXVisualInfo;
    glwin : XID;
  public
    { Public-Deklarationen }
  end;
...
Nun kann es richtig losgehen!
Nun kommt nämlich das Grauen der Windows-Benutzer dran: die OnCreate-Funktion! Diese
bearbeiten wir nun also:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
OpenGlInitialized := false;
end;
Nanu? Was soll das denn werden? Ist das alles?
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:
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;
So, das war eigentlich schon der größte Teil dieses ganzen Tuts. Nachdem wir das geschafft
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:
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;
Und was natürlich auch noch fehlt ist die Onresize-Prozedur (kennt man ja alles aus Teil
2(a)):

Delphi-Quellcode:
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;
Nun sind es nur noch zwei kleine Schritte zu vollständigen OpenGl-Initalisierung unter Kylix.
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:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
 if OpenGlInitialized then
  begin
    render;
  end;
end;
Und zu guter letzt muss noch die Render-Prozedur selbst her (man sollte sie im Quelltext über
das Timer-Event schreiben, da ansonsten der Timer evtl. die Render-Prozedur nicht finden
kann:

Delphi-Quellcode:
procedure render;
begin
 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); //Farb und Tiefenpuffer lschen
 glLoadIdentity;

 glXSwapBuffers(form1.dpy, form1.glwin);
end;
Hier kommt nun die erste (und letzte kleine Überaschung). Leider funktioniert der alte
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
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

 
Delphi 7 Enterprise
 
#3
  Alt 7. Mär 2004, 23:58
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:
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;
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.)

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.
  Mit Zitat antworten Zitat
Benutzerbild von Mr_T
Mr_T

 
Delphi 2005 Personal
 
#4
  Alt 8. Mär 2004, 11:40
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
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

 
Delphi 7 Enterprise
 
#5
  Alt 8. Mär 2004, 17:18
Zitat von Mr_T:
[...] bewegst und drehst du das Licht mit den Objekten mit.
Ühm, das sollte ja auch so sein . Es soll stationär relativ zu der Szene (=Objekten) sein, und nicht zur "Kamera". Oder hab ich das jetzt verwechselt?

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.
Dann klebt es an der Kamera, gell!? Hab schon fast alle möglichen Positionen des "glLightfv" in der Prozedur durch, und eines brachte zumindest für das Licht Erfolg:
Delphi-Quellcode:
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
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


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.
Kommt zeit, kommt Textur . Für meinen aktuellen Fall eher ungeeignet, da ich das "Life"-Progrämmchen (gibbet auch von Luckie) mal in 3D basteln will, und natürlich auch visualisieren. Und da dort ständig Massen an Würfeln "erzeugt" und "vernichtet" werden, würde ich den Aufwand pro Würfel gerne so niedrig wie möglich halten.

Danke dir schon mal!
dizzy
Fabian K.
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

 
Delphi 7 Enterprise
 
#6
  Alt 8. Mär 2004, 18:08
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.
  Mit Zitat antworten Zitat
mimi

 
FreePascal / Lazarus
 
#7
  Alt 8. Aug 2004, 09:36
@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:
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;
doch leider bewegen sich die objekte mit bzw. die position verändern sich
(ich verwende eine vorlage von delphiGL.com)
Michael Springwald
  Mit Zitat antworten Zitat
Benutzerbild von mischerr
mischerr

 
Delphi 12 Athens
 
#8
  Alt 8. Aug 2004, 13:53
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!
  Mit Zitat antworten Zitat
Jörn
 
#9
  Alt 8. Aug 2004, 17:33
2D in OpenGL? Gibts ein Tutorial auf www.delphigl.com
Hoffe das hilft weiter.
  Mit Zitat antworten Zitat
Benutzerbild von mischerr
mischerr

 
Delphi 12 Athens
 
#10
  Alt 8. Aug 2004, 17:58
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!
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es 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

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:28 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz