openglrotationlightingimmediate-mode

OpenGL: Why Lighting changing when Object Rotates?


The below code rotates a pyramid and a cube around their local axis (I believe). Why do both objects go light and dark with this code? Surely the light would come from one fixed position (like the sun) and the objects themselves would not go dark and light in entirety?

What causes this behaviour? This is old immediate mode. I am an OpenGL newbie.

It appears that the light source is "glued" to a face of each object. When each object rotates, it rotates it's light source along with it.

#include <windows.h>                            // Header File For Windows
#include <gl\gl.h>                              // Header File For The OpenGL32 Library
#include <gl\glu.h>                             // Header File For The GLu32 Library
#include <GL\glut.h>

static void resize(int width, int height)
{
    const float ar = (float) width / (float) height;

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

GLfloat     rtri  = 0.0;                          // Angle For The Triangle 
GLfloat     rquad = 0.0;                        // Angle For The Quad     
GLfloat     xPosCube = 0.0;

//--------------------------------------------------------------------------------------------
// DrawPyramid
//--------------------------------------------------------------------------------------------
void DrawPyramid( void )
{
    glLoadIdentity();
  glTranslatef( -1.5f, 0.0f, -6.0f );                   // Move Left 1.5 Units And Into The Screen 6.0

  glRotatef( rtri, 0.0f, 1.0f, 0.0f );              // Rotate The Triangle On The Y axis

    glBegin( GL_TRIANGLES );                    // Start Drawing The Pyramid

    // Face 1
      glVertex3f( 0.0f, 1.0f, 0.0f );           // Top Of Triangle (Front)
      glVertex3f( -1.0f, -1.0f, 1.0f );         // Left Of Triangle (Front)
      glVertex3f( 1.0f, -1.0f, 1.0f );          // Right Of Triangle (Front)

    // Face 2
      glVertex3f( 0.0f, 1.0f, 0.0f);            // Top Of Triangle (Right)
      glVertex3f( 1.0f,-1.0f, 1.0f);            // Left Of Triangle (Right)
      glVertex3f( 1.0f,-1.0f, -1.0f);           // Right Of Triangle (Right)

    // Face 3
      glVertex3f( 0.0f, 1.0f, 0.0f);            // Top Of Triangle (Back)
      glVertex3f( 1.0f,-1.0f, -1.0f);           // Left Of Triangle (Back)
      glVertex3f(-1.0f,-1.0f, -1.0f);           // Right Of Triangle (Back)

    // Face 4
      glVertex3f( 0.0f, 1.0f, 0.0f);            // Top Of Triangle (Left)
      glVertex3f(-1.0f,-1.0f,-1.0f);            // Left Of Triangle (Left)
      glVertex3f(-1.0f,-1.0f, 1.0f);            // Right Of Triangle (Left)
    glEnd();
}

//--------------------------------------------------------------------------------------------
// DrawCube
//--------------------------------------------------------------------------------------------
void DrawCube( void )
{
  glLoadIdentity();
    glTranslatef( 1.75f /* + xPosCube*/ ,0.0f,-7.0f + xPosCube);                // Move Right And Into The Screen

  glRotatef(rquad,1.0f,1.0f,1.0f);          // Rotate The Cube On X, Y & Z

    glBegin(GL_QUADS);

        glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Top)
        glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Top)
        glVertex3f(-1.0f, 1.0f, 1.0f);          // Bottom Left Of The Quad (Top)
        glVertex3f( 1.0f, 1.0f, 1.0f);          // Bottom Right Of The Quad (Top)

        glVertex3f( 1.0f,-1.0f, 1.0f);          // Top Right Of The Quad (Bottom)
        glVertex3f(-1.0f,-1.0f, 1.0f);          // Top Left Of The Quad (Bottom)
        glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Bottom)
        glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Bottom)

        glVertex3f( 1.0f, 1.0f, 1.0f);          // Top Right Of The Quad (Front)
        glVertex3f(-1.0f, 1.0f, 1.0f);          // Top Left Of The Quad (Front)
        glVertex3f(-1.0f,-1.0f, 1.0f);          // Bottom Left Of The Quad (Front)
        glVertex3f( 1.0f,-1.0f, 1.0f);          // Bottom Right Of The Quad (Front)

        glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Back)
        glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Back)
        glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Back)
        glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Back)

        glVertex3f(-1.0f, 1.0f, 1.0f);          // Top Right Of The Quad (Left)
        glVertex3f(-1.0f, 1.0f,-1.0f);          // Top Left Of The Quad (Left)
        glVertex3f(-1.0f,-1.0f,-1.0f);          // Bottom Left Of The Quad (Left)
        glVertex3f(-1.0f,-1.0f, 1.0f);          // Bottom Right Of The Quad (Left)

        glVertex3f( 1.0f, 1.0f,-1.0f);          // Top Right Of The Quad (Right)
        glVertex3f( 1.0f, 1.0f, 1.0f);          // Top Left Of The Quad (Right)
        glVertex3f( 1.0f,-1.0f, 1.0f);          // Bottom Left Of The Quad (Right)
        glVertex3f( 1.0f,-1.0f,-1.0f);          // Bottom Right Of The Quad (Right)

    glEnd();                        // Done Drawing The Quad
}

//--------------------------------------------------------------------------------------------
// DrawPyramidHiddenLinesPolygonOffset()
//--------------------------------------------------------------------------------------------
void DrawPyramidHiddenLinesPolygonOffset( void )
{
  // Draw cube - Hidden Line Removal with Polygon Offset.. 
  glEnable(GL_DEPTH_TEST);
  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  glColor4f(1.0f,0.0f,0.0f, 1.0f);          // Set The Color To Violet

  DrawPyramid();

  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  glEnable(GL_POLYGON_OFFSET_FILL);
  glPolygonOffset(1.0, 1.0);
  glColor4f(0.5f,0.0f,0.0f, 0.1f);          // Set The Color To Violet

  DrawPyramid();

  glDisable(GL_POLYGON_OFFSET_FILL);
}

//--------------------------------------------------------------------------------------------
// DrawCubeHiddenLinesPolygonOffset()
//--------------------------------------------------------------------------------------------
void DrawCubeHiddenLinesPolygonOffset( void )
{
  // Draw cube - Hidden Line Removal with Polygon Offset.. 
  glEnable(GL_DEPTH_TEST);
  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  glColor4f(1.0f,0.0f,1.0f, 1.0f);          // Set The Color To Violet

  DrawCube( FALSE );

  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  glEnable(GL_POLYGON_OFFSET_FILL);
  glPolygonOffset(1.0, 1.0);
  glColor4f(0.5f,0.0f,0.5f, 0.1f);          // Set The Color To Violet

  DrawCube( FALSE );

  glDisable(GL_POLYGON_OFFSET_FILL);
}

//--------------------------------------------------------------------------------------------
// DrawGLScene()
//--------------------------------------------------------------------------------------------
void DrawGLScene(void)
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // Do camera rotation first..

  // Now draw and rotate objects..
  DrawCubeHiddenLinesPolygonOffset();
  DrawPyramidHiddenLinesPolygonOffset();


    rtri  += 0.022f;                        // Increase The Rotation Variable For The Triangle 
    rquad -= 0.045f;                        // Decrease The Rotation Variable For The Quad     
  //xPosCube -= 0.0005f;

  glutSwapBuffers();
}

const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };

const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat high_shininess[] = { 100.0f };



void IdleFunc()
{
  glutPostRedisplay();
}


void KeyboardFunc( BYTE key, int x, int y )
{
  switch (key)
  {
     case 27: // Escape key
      //glutDestroyWindow( Win.id );
      exit (0);
      break;
  }
}


/* Program entry point */
int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Programming Techniques - 3D Spheres");

    glutKeyboardFunc( KeyboardFunc );
    glutReshapeFunc(resize);
    glutDisplayFunc( DrawGLScene );
    glutIdleFunc( IdleFunc );

    glClearColor(1,1,1,1);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    glEnable(GL_LIGHT0);
    glEnable(GL_NORMALIZE);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);

    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);

    glutMainLoop();

    return EXIT_SUCCESS;
}

Solution

  • You are not supplying any surface normals, but lighting depends on it. As a result, all of your vertices and faces have the same normal (GL's initial default is (0,1,0), iirc), which means that each face is lighted as if they all have the same angle to the light soruce. This normal just gets transformed around when you apply your rotation.