}
The following routine just sets up a point of view using gluLookAt. We set a point of view placed at 0, 5, 50 that is looking to 0, 0, 0 and that has the UP vector looking UP (0, 1, 0)! :D
void ProcessHelix() // Draws A Helix
{
GLfloat x; // Helix x Coordinate
GLfloat y; // Helix y Coordinate
GLfloat z; // Helix z Coordinate
GLfloat phi; // Angle
GLfloat theta; // Angle
GLfloat v,u; // Angles
GLfloat r; // Radius Of Twist
int twists = 5; // 5 Twists
GLfloat glfMaterialColor[]={0.4f,0.2f,0.8f,1.0f}; // Set The Material Color
GLfloat specular[]={1.0f,1.0f,1.0f,1.0f}; // Sets Up Specular Lighting
glLoadIdentity(); // Reset The Modelview Matrix
gluLookAt(0, 5, 50, 0, 0, 0, 0, 1, 0); // Eye Position (0,5,50) Center Of Scene (0,0,0)
// Up On Y Axis.
glPushMatrix(); // Push The Modelview Matrix
glTranslatef(0,0,-50); // Translate 50 Units Into The Screen
glRotatef(angle/2.0f,1,0,0); // Rotate By angle/2 On The X-Axis
glRotatef(angle/3.0f,0,1,0); // Rotate By angle/3 On The Y-Axis
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, glfMaterialColor);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
We then calculate the helix formula and render the spring. It's quite simple, I won't explain it, beacuse it isn't the main goal of this tutorial. The helix code was borrowed (and optimized a bit) from Listen Software friends. This is written the simple way, and is not the fastest method. Using vertex arrays would make it faster!
r=1.5f; // Radius
glBegin(GL_QUADS); // Begin Drawing Quads
for(phi=0; phi <= 360; phi+=20.0) // 360 Degrees In Steps Of 20
{
for(theta=0; theta<=360*twists; theta+=20.0) // 360 Degrees * Number Of Twists In Steps Of 20
{
v=(phi/180.0f*3.142f); // Calculate Angle Of First Point ( 0 )
u=(theta/180.0f*3.142f); // Calculate Angle Of First Point ( 0 )
x=float(cos(u)*(2.0f+cos(v) ))*r; // Calculate x Position (1st Point)
y=float(sin(u)*(2.0f+cos(v) ))*r; // Calculate y Position (1st Point)
z=float((( u-(2.0f*3.142f)) + sin(v) ) * r); // Calculate z Position (1st Point)
vertexes[0][0]=x; // Set x Value Of First Vertex
vertexes[0][1]=y; // Set y Value Of First Vertex
vertexes[0][2]=z; // Set z Value Of First Vertex
v=(phi/180.0f*3.142f); // Calculate Angle Of Second Point ( 0 )
u=((theta+20)/180.0f*3.142f); // Calculate Angle Of Second Point ( 20 )
x=float(cos(u)*(2.0f+cos(v) ))*r; // Calculate x Position (2nd Point)
y=float(sin(u)*(2.0f+cos(v) ))*r; // Calculate y Position (2nd Point)
z=float((( u-(2.0f*3.142f)) + sin(v) ) * r); // Calculate z Position (2nd Point)
vertexes[1][0]=x; // Set x Value Of Second Vertex
vertexes[1][1]=y; // Set y Value Of Second Vertex
vertexes[1][2]=z; // Set z Value Of Second Vertex
v=((phi+20)/180.0f*3.142f); // Calculate Angle Of Third Point ( 20 )
u=((theta+20)/180.0f*3.142f); // Calculate Angle Of Third Point ( 20 )
x=float(cos(u)*(2.0f+cos(v) ))*r; // Calculate x Position (3rd Point)
y=float(sin(u)*(2.0f+cos(v) ))*r; // Calculate y Position (3rd Point)
z=float((( u-(2.0f*3.142f)) + sin(v) ) * r); // Calculate z Position (3rd Point)
vertexes[2][0]=x; // Set x Value Of Third Vertex
vertexes[2][1]=y; // Set y Value Of Third Vertex
vertexes[2][2]=z; // Set z Value Of Third Vertex
v=((phi+20)/180.0f*3.142f); // Calculate Angle Of Fourth Point ( 20 )
u=((theta)/180.0f*3.142f); // Calculate Angle Of Fourth Point ( 0 )
x=float(cos(u)*(2.0f+cos(v) ))*r; // Calculate x Position (4th Point)
y=float(sin(u)*(2.0f+cos(v) ))*r; // Calculate y Position (4th Point)
z=float((( u-(2.0f*3.142f)) + sin(v) ) * r); // Calculate z Position (4th Point)
vertexes[3][0]=x; // Set x Value Of Fourth Vertex
vertexes[3][1]=y; // Set y Value Of Fourth Vertex
vertexes[3][2]=z; // Set z Value Of Fourth Vertex
calcNormal(vertexes,normal); // Calculate The Quad Normal
glNormal3f(normal[0],normal[1],normal[2]); // Set The Normal
// Render The Quad
glVertex3f(vertexes[0][0],vertexes[0][1],vertexes[0][2]);
glVertex3f(vertexes[1][0],vertexes[1][1],vertexes[1][2]);
glVertex3f(vertexes[2][0],vertexes[2][1],vertexes[2][2]);
glVertex3f(vertexes[3][0],vertexes[3][1],vertexes[3][2]);
}
}
glEnd(); // Done Rendering Quads
glPopMatrix(); // Pop The Matrix
}
This two routines (ViewOrtho and ViewPerspective) were coded to make it easy to draw in an orthogonal way and get back to perspective rendering with ease.
ViewOrtho simply sets the projection matrix, then pushes a copy of the actual projection matrix onto the OpenGL stack. The identity matrix is then loaded and an orthographic view with the current screen resolution is set up.
This way it is possible to draw using 2D coordinates with 0,0 in the upper left corner of the screen and with 640,480 in the lower right corner of the screen.
Finally, the modelview matrix is activated for rendering stuff.
ViewPerspective sets up projection matrix mode and pops back the non-orthogonal matrix that ViewOrtho pushed onto the stack. The modelview matrix is then selected so we can rendering stuff.
I suggest you keep these two procedures, it's nice being able to render in 2D without having to worry about the projection matrix!
void ViewOrtho() // Set Up An Ortho View
{
glMatrixMode(GL_PROJECTION); // Select Projection
glPushMatrix(); // Push The Matrix
glLoadIdentity(); // Reset The Matrix
glOrtho( 0, 640 , 480 , 0, –1, 1 ); // Select Ortho Mode (640x480)
glMatrixMode(GL_MODELVIEW); // Select Modelview Matrix
glPushMatrix(); // Push The Matrix
glLoadIdentity(); // Reset The Matrix
}
void ViewPerspective() // Set Up A Perspective View
{
glMatrixMode( GL_PROJECTION ); // Select Projection
glPopMatrix(); // Pop The Matrix
glMatrixMode( GL_MODELVIEW ); // Select Modelview
glPopMatrix(); // Pop The Matrix
}
Now it's time to explain how the fake radial blur effect is done:
We need to draw the scene so it appears blurred in all directions starting from the center. The trick is doing this without a major performance hit. We can't read and write pixels, and if we want compatibility with non kick-butt video cards, we can't use extensions or driver specific commands.