www.codeworx.org/opengl-tutorials/Tutorial 18: Quadratics

Lektion 18: Quadrics

Mit sogenannten Quadratics lassen sich recht komplexe Objekte zeichnen, die man mit den bisherigen Stand nur mit vielen unschönen FOR-Schleifen zeichnen und texturieren könnte. Es wird der Code aus Lektion 7 erweitert.

   #include <windows.h>// Header File For Windows
   #include <stdio.h>// Header File For Standard Input/Output
   #include <gl\gl.h>// Header File For The OpenGL32 Library
   #include <gl\glu.h>// Header File For The GLu32 Library
   #include <gl\glaux.h>// Header File For The GLaux Library
   HDChDC=NULL;// Private GDI Device Context
   HGLRChRC=NULL;// Permanent Rendering Context
   HWNDhWnd=NULL;// Holds Our Window Handle
   HINSTANCEhInstance;// Holds The Instance Of The Application
   boolkeys[256];// Array Used For The Keyboard Routine
   boolactive=TRUE;// Window Active Flag Set To TRUE By Default
   boolfullscreen=TRUE;// Fullscreen Flag Set To Fullscreen Mode By Default
   boollight;// Lighting ON/OFF
   boollp;// L Pressed?
   boolfp;// F Pressed?
   bool sp;// Spacebar Pressed?( NEW )
   intpart1;// Start Of Disc( NEW )
   intpart2;// End Of Disc( NEW )
   intp1=0;// Increase 1( NEW )
   intp2=1;// Increase 2( NEW )
   GLfloatxrot;// X Rotation
   GLfloatyrot;// Y Rotation
   GLfloat xspeed;// X Rotation Speed
   GLfloat yspeed;// Y Rotation Speed
   GLfloatz=-5.0f;// Depth Into The Screen
   GLUquadricObj *quadratic;// Storage For Our Quadratic Objects    ( NEW )
   GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };// Ambient    Light Values
   GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };// Diffuse Light Values
   GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };// Light Position
   GLuintfilter;// Which Filter To Use
   GLuinttexture[3];// Storage for 3 textures
   GLuint object=0;// Which Object To Draw( NEW )
   LRESULTCALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);// Declaration    For WndProc

Weiter zu InitGL(). Wir fügen 3 Zeilen hinzu um unser Quadratic zu initialisieren (Am besten kurz vor dem "return true"). Die erste Zeile initialisiert das Quadratic und speichert einen Zeiger auf die entsprechende Speicheradresse in "quadratic". Die zweite Zeile erstellt Normalen für das Objekt, damit die Beleuchtung funktioniert. Auch Texturmapping muss für dieses Objekt aktiviert werden (3. Zeile).

   quadratic=gluNewQuadric();// Create A Pointer To The Quadric Object ( NEW )
   gluQuadricNormals(quadratic, GLU_SMOOTH);// Create Smooth Normals ( NEW )
   gluQuadricTexture(quadratic, GL_TRUE);// Create Texture Coords ( NEW )

Die folgenden Zeilen sollten noch bekannt sein, zum Vergleich wird auch der Würfel aus Lektion 7 nocheinmal ausgegeben.

GLvoid glDrawCube()// Draw A Cube
{
   glBegin(GL_QUADS);// Start Drawing Quads
   // Front Face
   glNormal3f( 0.0f, 0.0f, 1.0f);// Normal Facing Forward
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);// Bottom Left Of The    Texture and Quad
   glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);// Bottom Right Of    The Texture and Quad
   glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);// Top Right Of The    Texture and Quad
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);// Top Left Of The Texture    and Quad
   // Back Face
   glNormal3f( 0.0f, 0.0f,-1.0f);// Normal Facing Away
   glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);// Bottom Right Of    The Texture and Quad
   glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);// Top Right Of The    Texture and Quad
   glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);// Top Left Of The    Texture and Quad
   glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);// Bottom Left Of    The Texture and Quad
   // Top Face
   glNormal3f( 0.0f, 1.0f, 0.0f);// Normal Facing Up
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);// Top Left Of The    Texture and Quad
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);// Bottom Left Of The    Texture and Quad
   glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);// Bottom Right Of The    Texture and Quad
   glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);// Top Right Of The    Texture and Quad
   // Bottom Face
   glNormal3f( 0.0f,-1.0f, 0.0f);// Normal Facing Down
   glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);// Top Right Of The    Texture and Quad
   glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);// Top Left Of The    Texture and Quad
   glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);// Bottom Left Of The    Texture and Quad
   glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);// Bottom Right Of    The Texture and Quad
   // Right face
   glNormal3f( 1.0f, 0.0f, 0.0f);// Normal Facing Right
   glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);// Bottom Right Of    The Texture and Quad
   glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);// Top Right Of The    Texture and Quad
   glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);// Top Left Of The Texture    and Quad
   glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);// Bottom Left Of The    Texture and Quad
   // Left Face
   glNormal3f(-1.0f, 0.0f, 0.0f);// Normal Facing Left
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);// Bottom Left Of    The Texture and Quad
   glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);// Bottom Right Of    The Texture and Quad
   glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);// Top Right Of The    Texture and Quad
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);// Top Left Of The    Texture and Quad
   glEnd();// Done Drawing Quads
}

Als nächstes die DrawGLScene-Funktion. Zuerst die üblichen Initialisierungen, danach folgt eine simple Fallunterscheidung um verschiedene Objekte ausgeben zu können, je nachdem welchenWert die Variable "object" hat. Im ersten Fall wird der Würfel ausgegeben (Sollte ja noch bekannt sein).

int DrawGLScene(GLvoid)// Here's Where We Do All The Drawing
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear The Screen And The    Depth Buffer
   glLoadIdentity();// Reset The View
   glTranslatef(0.0f,0.0f,z);// Translate Into The Screen
   glRotatef(xrot,1.0f,0.0f,0.0f);// Rotate On The X Axis
   glRotatef(yrot,0.0f,1.0f,0.0f);// Rotate On The Y Axis
   glBindTexture(GL_TEXTURE_2D, texture[filter]);// Select A Filtered Texture
   // This Section Of Code Is New ( NEW )
   switch(object)// Check object To Find Out What To Draw
   {
      case 0:// Drawing Object 1
       glDrawCube();// Draw Our Cube
      break;// Done

Das zweite Objekt ist ein Zylinder. Der erste Parameter (1.0f) legt den Radius an seiner Basis fest. Der zweite Parameter (auch 1.0f) ist der Radius an der Oberseite, der dritte legt die Höhe des Körpers fest. Die letzten beiden Werte sind ein Mass für die Dichte des Gitternetzes aus dem der Zylinder besteht, je höher diese ausfallen, destso weniger kantig wirkt das Objekt.

   case 1:// Drawing Object 2
    glTranslatef(0.0f,0.0f,-1.5f);// Center The Cylinder
    gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);// Draw Our Cylinder
   break;// Done

Das dritte mögliche Objekt sieht ungefähr aus wie eine CD. Der erste Parameter ist der Radius des Lochs in der Mitte der Scheibe, ist dieser 0.0f, gibts dieses natürlich nicht. 1.5f steht für den äußeren Radius, dieser sollte natürlich größer ausfallen als der innere. Die letzten beiden Parameter geben wieder die Dichte des Gitters an.

   case 2:// Drawing Object 3
    gluDisk(quadratic,0.5f,1.5f,32,32);// Draw A Disc (CD Shape)
   break;// Done

Und nun, die sollte hier nicht fehlen, eine Kugel. Der erste Parameter beschreibt den Radius, die letzten beiden die Dichte des Drahtgitters.

   case 3:// Drawing Object 4
    gluSphere(quadratic,1.3f,32,32);// Draw A Sphere
   break;// Done

Mithilfe der Zylinderfunktion lassen sich auch Kegel erstellen, indem der Radius "oben" oder "unten" auf 0.0f gesetzt wird, das fünfte Objekt ensteht.

   case 4:// Drawing Object 5
    glTranslatef(0.0f,0.0f,-1.5f);// Center The Cone
    gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);// A Cone With A Bottom Radius Of 0.0f
   break;// Done

Das letzte Objekt wird animiert indem eine Scheibe partiell ausgegeben wird. gluPartialDisk gleicht in den ersten 5 Parametern gluDisk, die letzten beiden werden in Grad (0-360) angegeben und bestimmen wieviel von der Scheibe zusehen sein soll ( Bei 0 und 360 wäre alles zusehen, bei 0 und 180 genau die Hälfte der Scheibe). Um Bewegung hinnein zubringen werden diese Werte bei jedem Durchlauf verändert.

   case 5:// Drawing Object 6
   part1+=p1;// Increase Start Angle
   part2+=p2;// Increase Sweep Angle
   if(part1>359)// 360 Degrees
   {
      p1=0;// Stop Increasing Start Angle
      part1=0;// Set Start Angle To Zero
      p2=1;// Start Increasing Sweep Angle
      part2=0;// Start Sweep Angle At Zero
   }

   if(part2>359)// 360 Degrees
   {
      p1=1;// Start Increasing Start Angle
      p2=0;// Stop Increasing Sweep Angle
   }

   gluPartialDisk(quadratic,0.5f,1.5f,32,32,part1,part2-part1);// A Disk Like The    One Before
   break;// Done
 };
 xrot+=xspeed;// Increase Rotation On X Axis
 yrot+=yspeed;// Increase Rotation On Y Axis
 return TRUE;// Keep Going

}


In KillGLWindow muss der Speicher des Quadratics wieder freigegeben werden, dies passiert mit gluDeleteQuadric.

   GLvoid KillGLWindow(GLvoid)// Properly Kill The Window
   {
       gluDeleteQuadric(quadratic);// Delete Quadratic - Free Resources

	(...)


Zum Schluss müssen nur noch die Tastatureingaben verarbeitet werden, diese Zeilen müssen in die entspechende Funktion aus Lektion 7 eingefügt werden.

   if (keys[' '] && !sp)// Is Spacebar Being Pressed?
   {
      sp=TRUE;// If So, Set sp To TRUE
      object++;// Cycle Through The Objects
      if(object>5)// Is object Greater Than 5?
      object=0;// If So, Set To Zero
   }

   if (!keys[' '])// Has The Spacebar Been Released?
   {
      sp=FALSE;// If So, Set sp To FALSE
   }


Und das wars auch schon, viel Spaß beim rumprobieren:

Jeff Molofee (NeHe) http://nehe.gamedev.net

Die Source Codes und Ausführbaren Dateien zu den Kursen liegen auf der Neon Helium Website

Übersetzt und leicht modifiziert von Hans-Jakob Schwer 23.10.2k2, www.codeworx.org