Quadrics

Quadrics

Quadrics are a way of drawing complex objects that would usually take a few FOR loops and some background in trigonometry.

We'll be using the code from lesson seven. We will add 7 variables and modify the texture to add some variety :)

#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

HDC		hDC=NULL;				// Private GDI Device Context
HGLRC		hRC=NULL;				// Permanent Rendering Context
HWND		hWnd=NULL;				// Holds Our Window Handle
HINSTANCE	hInstance;				// Holds The Instance Of The Application

bool	keys[256];					// Array Used For The Keyboard Routine
bool	active=TRUE;					// Window Active Flag Set To TRUE By Default
bool	fullscreen=TRUE;				// Fullscreen Flag Set To Fullscreen Mode By Default
bool	light;						// Lighting ON/OFF
bool	lp;						// L Pressed?
bool	fp;						// F Pressed?
bool    sp;						// Spacebar Pressed?	( NEW )

int	part1;						// Start Of Disc	( NEW )
int	part2;						// End Of Disc		( NEW )
int	p1=0;						// Increase 1		( NEW )
int	p2=1;						// Increase 2		( NEW )

GLfloat	xrot;						// X Rotation
GLfloat	yrot;						// Y Rotation
GLfloat xspeed;						// X Rotation Speed
GLfloat yspeed;						// Y Rotation Speed

GLfloat	z=-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

GLuint	filter;						// Which Filter To Use
GLuint	texture[3];					// Storage for 3 textures
GLuint  object=0;					// Which Object To Draw	( NEW )

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	// Declaration For WndProc

Okay now move down to InitGL(), We're going to add 3 lines of code here to initialize our quadratic. Add these 3 lines after you enable light1 but before you return true. The first line of code initializes the Quadratic and creates a pointer to where it will be held in memory. If it can't be created it returns 0. The second line of code creates smooth normals on the quadratic so lighting will look great. Other possible values are GLU_NONE, and GLU_FLAT. Last we enable texture mapping on our quadratic. Texture mapping is kind of awkward and never goes the way you planned as you can tell from the crate texture.

	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 )

Now I decided to keep the cube in this tutorial so you can see how the textures are mapped onto the quadratic object. I decided to move the cube into its own function so when we write the draw function it will appear more clean. Everybody should recognize this code. =P

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
}

Next is the DrawGLScene function, here I just wrote a simple if statement to draw the different objects. Also I used a static variable (a local variable that keeps its value everytime it is called) for a cool effect when drawing the partial disk. I'm going to rewrite the whole DrawGLScene function for clarity.

You'll notice that when I talk about the parameters being used I ignore the actual first parameter (quadratic). This parameter is used for all the objects we draw aside from the cube, so I ignore it when I talk about the parameters.

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

The second object we create is going to be a Cylinder. The first parameter (1.0f) is the radius of the cylinder at base (bottom). The second parameter (1.0f) is the radius of the cylinder at the top. The third parameter ( 3.0f) is the height of the cylinder (how long it is). The fouth parameter (32) is how many subdivisions there are "around" the Z axis, and finally, the fifth parameter (32) is the amount of subdivisions "along" the Z axis. The more subdivisions there are the more detailed the object is. By increase the amount of subdivisions you add more polygons to the object. So you end up sacrificing speed for quality. Most of the time it's easy to find a happy medium.

	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

The third object we create will be a CD shaped disc. The first parameter (0.5f) is the inner radius of the disk. This value can be zero, meaning there will be no hole in the middle. The larger the inner radius is, the bigger the hole in the middle of the disc will be. The second parameter (1.5f) is the outer radius. This value should be larger than the inner radius. If you make this value a little bit larger than the inner radius you will end up with a thing ring. If you make this value alot larger than the inner radius you will end up with a thick ring. The third parameter (32) is the number of slices that make up the disc. Think of slices like the slices in a pizza. The more slices you have, the smoother the outer edge of the disc will be. Finally the fourth parameter (32) is the number of rings that make up the disc. The rings are are similar to the tracks on a record. Circles inside circles. These ring subdivide the disc from the inner radius to the outer radius, adding more detail. Again, the more subdivisions there are, the slow it will run.

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

Our fourth object is an object that I know many of you have been dying to figure out. The Sphere! This one is quite simple. The first parameter is the radius of the sphere. In case you're not familiar with radius/diameter, etc, the radius is the distance from the center of the object to the outside of the object. In this case our radius is 1.3f. Next we have our subdivision "around" the Z axis (32), and our subdivision "along" the Z axis (32). The more subdivisions you have the smoother the sphere will look. Spheres usually require quite a few subdivisions to make them look smooth.

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

Our fifth object is created using the same command that we used to create a Cylinder. If you remember, when we were creating the Cylinder the first two parameters controlled the radius of the cylinder at the bottom and the top. To make a cone it makes sense that all we'd have to do is make the radius at one end Zero. This will create a point at one end. So in the code below, we make the radius at the top of the cylinder equal zero. This creates our point, which also creates our cone.

	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 .5 And A Height Of 2
		break;						// Done

Our sixth object is created with gluPartialDisc. The object we create using this command will look exactly like the disc we created above, but with the command gluPartialDisk there are two new parameters. The fifth parameter (part1) is the start angle we want to start drawing the disc at. The sixth parameter is the sweep angle. The sweep angle is the distance we travel from the current angle. We'll increase the sweep angle, which causes the disc to be slowly drawn to the screen in a clockwise direction. Once our sweep hits 360 degrees we start to increase the start angle. the makes it appear as if the disc is being erased, then we start all over again!

	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 the KillGLWindow() section of code, we need to delete the quadratic to free up system resources. We do this with the command gluDeleteQuadratic.

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

Now for the final part, they key input. Just add this where we check the rest of key input.

				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
				}

Thats all! Now you can draw quadrics in OpenGL. Some really impressive things can be done with morphing and quadrics. The animated disc is an example of simple morphing.

Everyone if you have time go check out my website, TipTup.Com 2000.

GB Schmick (TipTup)

Jeff Molofee (NeHe)

* DOWNLOAD Visual C++ Code For This Lesson.

* DOWNLOAD Borland C++ Builder 6 Code For This Lesson. ( Conversion by Christian Kindahl )
* DOWNLOAD C# Code For This Lesson. ( Conversion by Brian Holley )
* DOWNLOAD Code Warrior 5.3 Code For This Lesson. ( Conversion by Scott Lupton )
* DOWNLOAD Cygwin Code For This Lesson. ( Conversion by Stephan Ferraro )
* DOWNLOAD Delphi Code For This Lesson. ( Conversion by Michal Tucek )
* DOWNLOAD Dev C++ Code For This Lesson. ( Conversion by Dan )
* DOWNLOAD Euphoria Code For This Lesson. ( Conversion by Evan Marshall )
* DOWNLOAD Game GLUT Code For This Lesson. ( Conversion by Milikas Anastasios )
* DOWNLOAD Irix / GLUT Code For This Lesson. ( Conversion by Rob Fletcher )
* DOWNLOAD Java Code For This Lesson. ( Conversion by Jeff Kirby )
* DOWNLOAD JoGL Code For This Lesson. ( Conversion by Abdul Bezrati )
* DOWNLOAD LCC Win32 Code For This Lesson. ( Conversion by Robert Wishlaw )
* DOWNLOAD Linux Code For This Lesson. ( Conversion by Simon Werner )
* DOWNLOAD Linux/GLX Code For This Lesson. ( Conversion by Mihael Vrbanec )
* DOWNLOAD Linux/SDL Code For This Lesson. ( Conversion by Ti Leggett )
* DOWNLOAD LWJGL Code For This Lesson. ( Conversion by Mark Bernard )
* DOWNLOAD Mac OS Code For This Lesson. ( Conversion by Anthony Parker )
* DOWNLOAD Mac OS X/Cocoa Code For This Lesson. ( Conversion by Bryan Blackburn )
* DOWNLOAD MASM Code For This Lesson. ( Conversion by Christophe )
* DOWNLOAD Visual C++ / OpenIL Code For This Lesson. ( Conversion by Denton Woods )
* DOWNLOAD Pelles C Code For This Lesson. ( Conversion by Pelle Orinius )
* DOWNLOAD SDL Code For This Lesson. ( Conversion by Ken Rockot )
* DOWNLOAD Visual Basic Code For This Lesson. ( Conversion by The Gilb )
* DOWNLOAD Visual Studio .NET Code For This Lesson. ( Conversion by Grant James )

 

< Lesson 17Lesson 19 >