Textures & Lighting

The following code presents two spinning spheres that are textured, but I’m certain it can be done much better. In fact, the code is cobbled together from miscellaneous sources. (It uses GLFW…)

Can the drawsphere function better encapsulate each sphere so that they can be independently manipulated. From my quick tests it seems that I couldn’t have one shaded a flat color while the other was textured.

With respect to lighting, it doesn’t work from what I can see. Perhaps I have incorrectly positioned the light source. — still learning the very basics…

Any quick pointers would be appreciated. I’d like to start with a simple example that is well constructed, and then build from there.

Thanks.

 
#include <stdio.h>
#include <GL/glfw.h>
#include <gl/glu.h>
#include <gl/glut.h>

static GLfloat theta[] = {0.0,0.0,0.0};
static GLint axis = 0;

GLuint texture_id[2];

GLfloat  ambient_light[] = {0.8, 0.8, 0.2, 1.0};
GLfloat   source_light[] = {1.0, 1.0, 1.0, 1.0};
GLfloat      light_pos[] = {0.0, 3.0, 4.0, 1.0};


void drawsphere()
{
	glPushMatrix();
	glBindTexture(GL_TEXTURE_2D, texture_id[1]);
	glTranslatef(1.3, 0.0, 0.0);
 	glRotatef( theta[0], 0.0f, 1.0f, 0.0f );
	GLUquadricObj* sph1 = gluNewQuadric();
	gluQuadricOrientation (sph1, GLU_OUTSIDE);
	gluQuadricDrawStyle(sph1, GLU_FILL);
	gluQuadricTexture(sph1, GL_TRUE);
	gluQuadricNormals(sph1, GL_TRUE);	
	glColor3f ( 1.0, 1.0, 0.0);
	gluSphere(sph1, 1.0, 50.0, 50.0);
	gluDeleteQuadric(sph1);
	glPopMatrix();

	glPushMatrix();
	glBindTexture(GL_TEXTURE_2D, texture_id[0]);
	glTranslatef(-1.3, 0.0, 0.0);
	GLUquadricObj* sph2 = gluNewQuadric();
	gluQuadricOrientation (sph2, GLU_OUTSIDE);
	gluQuadricDrawStyle(sph2, GLU_FILL);
	gluQuadricTexture(sph2, GL_TRUE);
	gluQuadricNormals(sph2, GL_SMOOTH);	
 	glRotatef( theta[0], 0.0f, 1.0f, 0.0f );
	gluSphere(sph2, 1.0, 50.0, 50.0);
	gluDeleteQuadric(sph2);
	glPopMatrix();
	
	glFlush();
}


int main( void )
{
    int     width, height, running, frames, x, y;
    double  t, t0;

    glfwInit();

   // Enable material properties for lighting
 glEnable ( GL_COLOR_MATERIAL );
   glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
    
   glEnable ( GL_LIGHTING );
   glLightModelfv ( GL_LIGHT_MODEL_AMBIENT, ambient_light );
   glLightfv ( GL_LIGHT0, GL_DIFFUSE,  source_light );
   glLightfv ( GL_LIGHT0, GL_POSITION, light_pos    );
   glEnable  ( GL_LIGHT0 );

    // Open OpenGL window
    if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_WINDOW ) )
    {
        glfwTerminate();
        return 0;
    }

   // Get and select a texture object ID
    glGenTextures( 2, texture_id );
    glBindTexture( GL_TEXTURE_2D, texture_id[0] );
    if( !glfwLoadTexture2D( "mipmaps.tga", GLFW_BUILD_MIPMAPS_BIT ) )
    {
        glfwTerminate();
        return 0;
    }
    glBindTexture( GL_TEXTURE_2D, texture_id[1] );
    if( !glfwLoadTexture2D( "one.tga", GLFW_BUILD_MIPMAPS_BIT ) )
    {
        glfwTerminate();
        return 0;
    }
   

   glEnable ( GL_CULL_FACE );
   glEnable( GL_TEXTURE_2D );

   // Disable vertical sync (on cards that support it)
    glfwSwapInterval( 0 );

    running = GL_TRUE;
    frames = 0;
    t0 = glfwGetTime();

    while( running )
    {
        // Get time and mouse position
        t = glfwGetTime();
	frames ++;

        // Get window size (may be different than the requested size)
        glfwGetWindowSize( &width, &height );
        height = height > 0 ? height : 1;

        glViewport( 0, 0, width, height );

        glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        gluPerspective( 65.0f, (GLfloat)width/(GLfloat)height, 1.0f, 300.0f );

        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
        gluLookAt( 0.0f, 0.0f, 4.0f,    
                   0.0f, 0.0f, 0.0f,   
                   0.0f, 1.0f, 0.0f ); 

	drawsphere();
	glfwSwapBuffers();
	
	theta[axis] += 0.1;
	if(theta[axis] > 360.0 ) theta[axis] -= 360.0;

	running = !glfwGetKey( GLFW_KEY_ESC ) &&
                  glfwGetWindowParam( GLFW_OPENED );
    }

    glfwTerminate();
    return 0;
}

 

pmac,

it might help to separate your tasks a little. Consider the process of drawing something as three separate stages:

  • You want to specify the the position and orientation of your object somewhere in the world.

  • You want to specify the render state of the object: lights, materials, textures, shaders, and so on.

  • You want to specify the geometry to draw, a sphere, in your case, but it could be anything.

Position, state, and geometry, with these three things more or less separated, generalizing the drawing process gets a lot easier. Try to group things logically.

Take your sphere, the geometry of a sphere doesn’t really change, just its position and rotation. So a drawSphere() function would need do little more than, well, position and draw a sphere

void drawSphere( Vector pos, float radius, int slices, int stacks ){
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glTranslatef( pos.x, pos.y, pos.z );
gluSphere( mySphere, radius, slices, stacks );
glPopMatrix();
}

Since you can use the same sphere repeatedly, you might consider creating a single sphere at program start.

As for the lighting, keep in mind that the gl transforms light positions with the modelview matrix. So if you want your positions unmodified, load an identity on the modelview matrix stack before setting them.