Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I fixate a light source in OpenGL while rotating an object?

I have a glutSolidTeapot (which has its surface normals generated automatically according to opengl.org) and a light source which is emitting diffuse light. The problem comes when I try to rotate the teapot: it seems like the light source is doing the rotation as well, not remaining in the same position I defined it (it essentially follows the teaspot). As you can see in my code, I only modify the lighting position upon initialization, so it is not subjected to glRotatef(), since its called after setting the light position.

Despite spending numerous hours trying to solve this problem, I really have no idea what this kind of behavior can be attributed to.

Pasting glEnable(GL_NORMALIZE); in the initialization does not solve the problem neither.

I think the desired output should be a teapot with a shiny right side (since the light is coming from that direction), no matter what angle the teapot is rotated by.

If you want to test my code, press Space to rotate the teapot.

#include <math.h>
#include <stdlib.h>

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#include <windows.h>     
#endif

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

void onInitialization( ) { //creating the light source
 glEnable(GL_LIGHTING);
 glEnable(GL_DEPTH_TEST); 

 GLfloat diffuse[]={0.8, 0.8, 0.8, 1.0};
 GLfloat pos[]={0.5, 0.0, 0.8, 0.0};

 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
 glLightfv(GL_LIGHT0, GL_POSITION, pos);

 glEnable(GL_LIGHT0);

 glRotatef(-90, 1, 0, 0); //we want to see the top of the teapot
}

void onDisplay( ) {
    glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 //rotating on every frame (for testing purposes only)
 glRotatef(5, 0,1,0);
 glutSolidTeapot(0.4);

    glFinish();
    glutSwapBuffers();
}


void onKeyboard(unsigned char key, int x, int y) {
 if (key==32){ //do rotation upon hitting the Space key
  glutPostRedisplay();
 }
}

int main(int argc, char **argv) {
    glutInit(&argc, argv); 
    glutInitWindowSize(600, 600);
    glutInitWindowPosition(100, 100);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("Teapot");

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    onInitialization();

    glutDisplayFunc(onDisplay);
    glutKeyboardFunc(onKeyboard);

    glutMainLoop();

    return 0;
}
like image 795
Attila Kun Avatar asked Nov 18 '09 18:11

Attila Kun


2 Answers

I think changing

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

to

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

is a good place to start.

like image 175
MaR Avatar answered Nov 15 '22 03:11

MaR


I also think your application "destroys" the modelview matrix; it's never re-computed from scratch. You should start each frame with a LoadIdentity(), then emit the lightsource, then rotate as desired, and finally emit the geometry.

This doesn't work, this doesn't work, this doesn't work, lalalalalalalala, and the FAQ is patently wrong, plain and simple.

Emitting the light just after glLoadIdentity() in order to get a camera-bound light will work in simple cases when you only translate, or only rotate the model around the origin. But when you start doing non-trivial, non-hello-world things like rotating an object around a point different than the origin (translate(-v), rotate(angle), translate(v)) and then moving it so that the rotation center is brought in front of the camera, then the "load identity, place light" technique starts failing spectacularly and in ways that make it very hard to deduce what is even going on.

No, I don't know the solution.

like image 23
BASTA Avatar answered Nov 15 '22 04:11

BASTA