Lektion 18
Quadrics
Quadrics sind eine Möglichkeit komplexe Objekte zu zeichen, die normalerweise mehrere FOR-Schleifen und einiges Hintergrundwissen in Trigonometrie benötigen würden.
Wir werden den Code aus Lektion sieben verwenden. Wir werden sieben Variablen hinzufügen und die Texturen ein wenig verändern um etwas Abwechslung hinein zu bringen :)
#include <windows.h> // Header Datei für Windows
#include <stdio.h> // Header Datei für Standard Eingabe/Ausgabe
#include <gl\gl.h> // Header Datei für die OpenGL32 Library
#include <gl\glu.h> // Header Datei für die GLu32 Library
#include <gl\glaux.h> // Header Datei für die GLaux Library
HDC hDC=NULL; // Privater GDI Device Context
HGLRC hRC=NULL; // Permanenter Rendering Context
HWND hWnd=NULL; // Enthält unser Fenster-Handle
HINSTANCE hInstance; // Enthält die Instanz der Applikation
bool keys[256]; // Array das für die Tastatur Routine verwendet wird
bool active=TRUE; // Fenster Aktiv Flag standardmäßig auf TRUE gesetzt
bool fullscreen=TRUE; // Fullscreen Flag ist standardmäßig auf TRUE gesetzt
bool light; // Beleuchtung AN/AUS
bool lp; // L gedrückt?
bool fp; // F gedrückt?
bool sp; // Leertaste gedrückt? ( NEU )
int part1; // Start der Disc ( NEU )
int part2; // Ende der Disc ( NEU )
int p1=0; // Increase 1 ( NEU )
int p2=1; // Increase 2 ( NEU )
GLfloat xrot; // X Rotation
GLfloat yrot; // Y Rotation
GLfloat xspeed; // X Rotation Geschwindigkeit
GLfloat yspeed; // Y Rotation Geschwindigkeit
GLfloat z=-5.0f; // Tiefe in den Bildschirm
GLUquadricObj *quadratic; // Speicher für unsere Quadratic Objecte ( NEU )
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; // Ambiente Licht Werte
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; // Diffuse Licht Werte
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f }; // Licht Position
GLuint filter; // Welcher Filter benutzt werden soll
GLuint texture[3]; // Speicher für 3 Texturen
GLuint object=0; // Welches Object gezeichnet werden soll ( NEU )
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Deklaration für WndProc
Okay, gehen Sie nun runter zu IniGL(). Wir fügen hier 3 Zeilen Code ein, um unser Qudaratic zu initialisieren. Fügen Sie die 3 Zeilen hinter dem Teil ein, wo Sie light1 aktiveren, aber noch bevor Sie True zurückgeben. Die erste Codezeile initialisiert den Quadratic und erzeugt einen Zeiger auf den Speicherbereich, wo er sich befinden wird. Wenn er nicht erzeugt werden kann, wird 0 zurückgegeben. Die zweite Codezeile erzeugt die Normalen für das Quadratic, so das die Beleuchtugn gut aussieht. Andere mögliche Werte währen GLU_NONE udn GLU_FLAT. Als letztes aktiveren Textur-Mapping für unser Quadratic. Textur-Mapping ist irgendwie ziemlich linkisch und funktioniert nie so, wie sie sich es vorstellen, so wie sie es schon von der Kisten-Textur kennen.
quadratic=gluNewQuadric(); // erzeugt einen Zeiger auf das Quadric Obkect ( NEU )
gluQuadricNormals(quadratic, GLU_SMOOTH); // erzeugt Normalen ( NEU )
gluQuadricTexture(quadratic, GL_TRUE); // erzeugt Textur Koordinaten ( NEU )
Nun habe ich mich entschlossen, den Würfel in diesem Tutorial beizubehalten, so dass Sie sehen können, wie Texturen auf Qudratic-Objekte gemapped werden. Ich habe mich entschlossen den Würfel in eine eigen Funktion zu verschieben, so das die Zeichnen-Funktion beim neu schreiben sauberer aussieht. Jeder sollte diesen Code wiedererkennen. =P
GLvoid glDrawCube() // Zeichne einen Würfel
{
glBegin(GL_QUADS); // Beginne Qudrate zu zeichnen
// Front Face
glNormal3f( 0.0f, 0.0f, 1.0f); // Normalen die forwärts zeigen
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Unten Links der Textur und des Qudrats
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Unten rechts der Textur und des Qudrats
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Oben rechts der Textur und des Qudrats
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Oben Links der Textur und des Qudrats
// Back Face
glNormal3f( 0.0f, 0.0f,-1.0f); // Normal Facing Away
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Unten rechts der Textur und des Qudrats
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Oben rechts der Textur und des Qudrats
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Oben Links der Textur und des Qudrats
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Unten Links der Textur und des Qudrats
// Top Face
glNormal3f( 0.0f, 1.0f, 0.0f); // Normal Facing Up
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Oben Links der Textur und des Qudrats
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Unten Links der Textur und des Qudrats
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Unten rechts der Textur und des Qudrats
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Oben rechts der Textur und des Qudrats
// Bottom Face
glNormal3f( 0.0f,-1.0f, 0.0f); // Normal Facing Down
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Oben rechts der Textur und des Qudrats
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Oben Links der Textur und des Qudrats
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Unten Links der Textur und des Qudrats
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Unten rechts der Textur und des Qudrats
// Right face
glNormal3f( 1.0f, 0.0f, 0.0f); // Normal Facing Right
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Unten rechts der Textur und des Qudrats
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Oben rechts der Textur und des Qudrats
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Oben Links der Textur und des Qudrats
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Unten Links der Textur und des Qudrats
// Left Face
glNormal3f(-1.0f, 0.0f, 0.0f); // Normal Facing Left
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Unten Links der Textur und des Qudrats
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Unten rechts der Textur und des Qudrats
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Oben rechts der Textur und des Qudrats
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Oben Links der Textur und des Qudrats
glEnd(); // Done Drawing Quads
}
Als nächstes ist die DrawGLScene-Funktion dran, wo ich eine einfache IF-Abfrage benutzt habe, um die einzelnen Objekte zu zeichnen. Außerdem habe ich eine statische Variable benutzt (eine lokale Variable, welche ihren Wert jeweils behält wenn sie aufgerufen wird), um einen coolen Effekt zu erzielen, wenn Teile der Disk gezeichnet werden. Ich schreibe die komplette DrawGLScene-Funktion der Übersicht halber komplett neu.
Sie werden bemerken, wenn ich über die benutzten Parameter spreche, ignoriere ich den eigentlichen ersten Parameter (quadratic). Dieser Parameter wird für alle Objekte benutzt, die wir neben dem Würfel zeichnen, weshalb ich ihn ignoriere, wenn ich über die Parameter spreche.
int DrawGLScene(GLvoid) // Hier kommt der ganze Zeichnen-Kram hin
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Löscht den Bildschirm und den Depth-Buffer
glLoadIdentity(); // Resettet die Ansicht (View)
glTranslatef(0.0f,0.0f,z); // In den Bildschirm hineinbewegen
glRotatef(xrot,1.0f,0.0f,0.0f); // Rotiere auf der X-Achse
glRotatef(yrot,0.0f,1.0f,0.0f); // Rotiere auf der X-Achse
glBindTexture(GL_TEXTURE_2D, texture[filter]); // Wähle eine Filter-Textur
// Dieser Code-Ausschnitt ist neu ( NEU )
switch(object) // Überprüfe object um herauszufinden, was gezeichnet werden soll
{
case 0: // Zeichne Objekt 1
glDrawCube(); // Zeichne unseren Würfel
break; // Fertig
Das zweite Objekt, das wir erzeugen, wird ein Zylinder sein. Der erste Parameter (1.0f) ist der Radius des Zylinders an seiner Basis (Boden). Der zweite Parameter (1.0f) ist der Radius des Zylinders an der Spitze. der dritte Parameter (3.0f) ist die Höhe des Zylinders (wie lang er ist). Der vierte Parameter (32) gibt an, wieviele Unterteilungen um die Z-Achse "herum" sind und letztendlich der fünfte Parameter (32) enthält die Anzahl der Unterteilungen "entlängs" der Z-Achse. Je mehr Unterteilungen es gibt, desto detailierter ist das Objekt. Indem Sie die Anzahl der Unterteilungen erhöhen, fügen Sie mehr Polygone dem Objekt hinzu. Demnach kaufen Sie sich Qualität mittel Geschwindigkeitseinbußen. Meistens ist es recht einfach ein gesundes Mittelmaß zu finden.
case 1: // Zeichne Objekt 2
glTranslatef(0.0f,0.0f,-1.5f); // Zentriere den Zylinder
gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32); // Zeichne unseren Zylinder
break; // Fertig
Das dritte Objekt das wir erzeugen hat die Form einer CD. Der erste Parameter (0.5f) ist der innere Radius der Disk. Dieser Wert kann gleich null sein, wenn kein Loch in der Mitte gewünscht ist. Je größer der innere Radius, desto größer ist das Loch in der Mitte der Disc. Der zweite Parameter (1.5f) ist der äußere Radius. Dieser Wert sollte größer sein, als der innere Radius. Wenn Sie ihn ein klein wenig größer als den inneren Radius machen, erhalten Sie einen dünnen Ring. Wenn Sie ihn wesentlich größer machen, werden Sie einen dicken Ring erhalten. Der dritte Parameter (32) ist die Anzahl der Scheiben aus der die Disk besteht. Denken Sie bei Scheiben an Pizza-Stücke. Die mehr Scheiben Sie haben, desto runter ist sind die äußeren Ecken der Disc. Letztendlich enthält der vierte Parameter (32) die Anzahl der Ringe, aus der die Diskette besteht. Die Ringe sind ähnlich den Spuren einer Schallplatte. Kreise innerhalb von Kreisen. Diese Ringe unterteilen die Disk vom inneren Radius bis zum äußeren Radius und bringen mehr Detail. Nochmal, je mehr Unterteilungen es gibt, desto langsamer wird es laufen.
case 2: // Zeichne Objekt 3
gluDisk(quadratic,0.5f,1.5f,32,32); // Zeichne eine Disc (CD Form)
break; // Fertig
Unser viertes Objekt ist ein Objekt, von dem ich weiß, dass viele Schwierigkeiten hatten mit ihr hatten. Die Sphere (Kugel)! Diese ist relativ simpel. Der erste Parameter ist der Radius der Sphere. Für den Fall, dass Sie mit Radius/Diameter, etc. nicht vertraut sind, der Radius ist der Abstand vom Mittelpunkt des Objekts zum äußeren Rand des Objektes. In diesem Fall ist unser Radius 1.3f. Als nächstes haben wir unsere Unterteilungen um die Z-Achse "herum" (32) und unsere Unterteilungen "entlängs" der Z-Achse (32) Je mehr Unterteilungen Sie haben, desto glatter wir die Spehre aussehen. Spehren benötigen in der Regel recht wenig Unterteilungen, damit sie gut aussehen.
case 3: // Zeichne Objekt 4
gluSphere(quadratic,1.3f,32,32); // Zeichne eine Sphere
break; // Fertig
Unser fünftes Objekt wird erzeugt, in dem der selbe Befehl benutzt wird, den wir schon zur Erzeugung des Zylinders benutzt haben. Wenn Sie sich erinnern, als wir den Zylinder erzeugten kontrollierten die ersten beiden Parameter den Radius des Zylinders am Boden und an der Spitze. Um einen Kegel zu erhalten, klingt es logisch, dass wir den Radius an einem Ende einfach 0 setzen. Das erzeugt einen Punkt am entsprechenden Ende. Dementsprechend setzen wir den Radius der Spitze im unteren Code auf null. Das erzeugt unseren Punkt, wodurch auch unser Kegel erzeugt wird.
case 4: // Zeichne Objekt 5
glTranslatef(0.0f,0.0f,-1.5f); // Zentriere den Kegel
gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32); // Ein Kegel mit unterem Raidus von 0.5f und einer Höhe von 2
break; // Fertig
Unser sechstes Objekt wird mit gluPartialDisc erzeugt. Das Objekt, dass wir mit diesem Befehl erzeugen, sieht genauso aus, wie die Disk, die wir vorhin erzeugt haben, mit dem Unterschied, dass der Befehl gluPartialDisc zwei neue Parameter hat. Der fünfte Parameter (part1) ist der Anfangs-Winkel ab wo wir die Disc zeichnen wollen. Der sechste Parameter ist der Sweep-Winkel. Der Sweep-Winkel ist die Distanz die wir vom aktuellen Winkel aus zurücklegen. Wir erhöhen den Sweep-Winkel, was ein langsames zunehmen im Uhrzeigersinn der Disc während des zeichnens, zur Folge hat. Wenn der Sweep-Winkel 360 Grad erreicht hat, erhöhen wir den Anfangs-Winkel, wodurch die Disc wieder langsam abnimmt. Danach starten wir erneut von vorne.
case 5: // Zeichne Objekt 6
part1+=p1; // Inkrementiere Start-Winkel
part2+=p2; // Inkrementiere Sweep-Winkel
if(part1>359) // 360 Grad
{
p1=0; // Stoppe mit der Inkrementierung des Anfangs-Winkels
part1=0; // Setze Anfangs-Winkel auf 0
p2=1; // Beginne mit der Inkrementierung des Sweep-Winkels
part2=0; // Starte Sweep-Winkel bei 0
}
if(part2>359) // 360 Grad
{
p1=1; // Starte Inkrementierung des Anfangs-Winkel
p2=0; // Stoppe Inkrementierung des Sweep-Winkels
}
gluPartialDisk(quadratic,0.5f,1.5f,32,32,part1,part2-part1); // Eine Disk wie die davor
break; // Fertig
};
xrot+=xspeed; // Inkrementiere Rotation auf der X-Achse
yrot+=yspeed; // Inkrementiere Rotation auf der Y-Achse
return TRUE; // Weiter geht's
}
Im KillGLWindow() Codesegment müssen wir den Quadratic wieder löschen, um den Speicher freizugeben. Wir machen das mit dem Befehl gluDeleteQuadratic.
GLvoid KillGLWindow(GLvoid) // Entferne das Fenster korrekt
{
gluDeleteQuadric(quadratic); // Lösche Quadratic - Gebe Ressourcen wieder frei
Nun zum letzten Teil, die Tasten-Eingabe. Fügen Sie das einfach da ein, wo wir den Rest der Tastatur-Eingabe überprüfen.
if (keys[' '] && !sp) // Wurde die Leertaste gedrückt?
{
sp=TRUE; // Wenn ja, setze sp auf TRUE
object++; // wechsle durch die Objekte
if(object>5) // Ist object größer als 5?
object=0; // Wenn ja, dann auf 0 setzen
}
if (!keys[' ']) // Wurde die Leertaste wieder losgelassen
{
sp=FALSE; // Wenn ja, dann setze sp auf FALSE
}
Das war's! Nun können Sie Quadrics in OpenGL zeichnen. Einige wirklich beeindruckende Dinge können mit Morphing und Quadrics gemacht werden. Die animierte Disk ist ein Beispiel einfachen Morphens.
All die Zeit haben, sich meine Web-Seite anzuschauen: TipTup.Com 2000.
GB Schmick (TipTup)
Jeff Molofee (NeHe)
* DOWNLOAD Visual C++ Code für diese Lektion.
* DOWNLOAD Borland C++ Builder 6 Code für diese Lektion. ( Conversion by Christian Kindahl )
* DOWNLOAD C# Code für diese Lektion. ( Conversion by Brian Holley )
* DOWNLOAD Code Warrior 5.3 Code für diese Lektion. ( Conversion by Scott Lupton )
* DOWNLOAD Cygwin Code für diese Lektion. ( Conversion by Stephan Ferraro )
* DOWNLOAD Delphi Code für diese Lektion. ( Conversion by Michal Tucek )
* DOWNLOAD Dev C++ Code für diese Lektion. ( Conversion by Dan )
* DOWNLOAD Euphoria Code für diese Lektion. ( Conversion by Evan Marshall )
* DOWNLOAD Game GLUT Code für diese Lektion. ( Conversion by Milikas Anastasios )
* DOWNLOAD Irix / GLUT Code für diese Lektion. ( Conversion by Rob Fletcher )
* DOWNLOAD Java Code für diese Lektion. ( Conversion by Jeff Kirby )
* DOWNLOAD JoGL Code für diese Lektion. ( Conversion by Abdul Bezrati )
* DOWNLOAD LCC Win32 Code für diese Lektion. ( Conversion by Robert Wishlaw )
* DOWNLOAD Linux Code für diese Lektion. ( Conversion by Simon Werner )
* DOWNLOAD Linux/GLX Code für diese Lektion. ( Conversion by Mihael Vrbanec )
* DOWNLOAD Linux/SDL Code für diese Lektion. ( Conversion by Ti Leggett )
* DOWNLOAD LWJGL Code für diese Lektion. ( Conversion by Mark Bernard )
* DOWNLOAD Mac OS Code für diese Lektion. ( Conversion by Anthony Parker )
* DOWNLOAD Mac OS X/Cocoa Code für diese Lektion. ( Conversion by Bryan Blackburn )
* DOWNLOAD MASM Code für diese Lektion. ( Conversion by Christophe )
* DOWNLOAD Visual C++ / OpenIL Code für diese Lektion. ( Conversion by Denton Woods )
* DOWNLOAD Pelles C Code für diese Lektion. ( Conversion by Pelle Orinius )
* DOWNLOAD SDL Code für diese Lektion. ( Conversion by Ken Rockot )
* DOWNLOAD Visual Basic Code für diese Lektion. ( Conversion by The Gilb )
* DOWNLOAD Visual Studio .NET Code für diese Lektion. ( Conversion by Grant James )
Deutsche Übersetzung: Joachim Rohde
Der original Text ist hier zu finden.
Die original OpenGL Tutorials stammen von NeHe's Seite.