I’m having troubles with creating a rectangular surface that has a cone-like spotlight pointing on it. So far, I’ve tried to create a 2D cube surface (glutSolidCube()) and use GL_SPOT_XXX to create the spotlight. But I don’t for what reason, the light just keeps scattering all over the surface instead of gather into a spot.
So here is my code so far, you can just focus on the init_light() and display() functions. The other functions are there for you to reference if you need to 🙂
void rotateCamera()
{
/* Rotate camera 2 degrees about selected axis */
theta[axis] += dtheta;
if (theta[axis] > 360.0 ) theta[axis] -= 360.0;
glutPostRedisplay();
}
void computeCameraPosition() {
GLdouble M[16];
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(centroid[0], centroid[1], centroid[2]);
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
glTranslatef(-centroid[0], -centroid[1], -centroid[2]);
glGetDoublev(GL_MODELVIEW_MATRIX, M);
GLdouble newvec[16];
glMultMatrixd(init_vec);
glGetDoublev(GL_MODELVIEW_MATRIX, newvec);
glPopMatrix();
/* the 1st and 2nd columns are the eye position and new y-axis direction */
memcpy(eye, newvec, sizeof(GLdouble)*4);
memcpy(yaxis, newvec+4, sizeof(GLdouble)*4);
}
void init_light()
{
GLfloat spot_direction[] = { 1.0, 1.0, 0.0 };
glLightfv( GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction );
glLightf( GL_LIGHT0, GL_SPOT_EXPONENT, 2.0 );
glLightf( GL_LIGHT0, GL_SPOT_CUTOFF, 45.0 );
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
}
void display() {
computeCameraPosition();
glClearColor(0.9, 0.9, 0.9, 1.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eye[0], eye[1], eye[2],
centroid[0], centroid[1], centroid[2],
yaxis[0], yaxis[1], yaxis[2]);
glutSolidCube(2.0);
glFlush();
glutSwapBuffers();
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 800);
glutInitWindowPosition (200, 100);
glutCreateWindow("Scene Editor");
init_light();
glutDisplayFunc(display);
glutMainLoop();
}
Standard fixed function OpenGL illumination is only evaluated at the vertex positions and the determined colours interpolated over the primitives. So get a spotlight effect, the illumination must be evaluated with high resolution. You can achieve this by either tesselating your plane, or by using a fragment shader that does per fragment lighting.
EDIT to answer comment
Tesselation
Tesselation means, subdividing your plane into a large number of “patches”. Like this:
→
Per fragment lighting
Per fragment lighting means, that the lighting equation is evaluated at each rasterized fragment (a fragment is what’s commonly referred to a pixel). For this a fragment shader is used, i.e. a small program load into the graphics processor (GPU), that’s executed for each fragment/pixel of the rasterized primitive (triangle, line, point).
Lighthouse3D has a tutorial about it: http://www.lighthouse3d.com/tutorials/glsl-tutorial/spot-light-per-pixel/ I recommend you read the full GLSL tutorial there, to get an idea, what’s going on.