Simple Light

Freya - February 5, 2010

OpenGL light example

Here we’ll look at an example of a simple light. We draw a static ball in the middle that will serve us as a background. Four small balls will move around the big one and represent different lights. These small balls are not actually lights, but are there to show the color and position of the light.

Read also: How to draw a Space Cube in OpenGL

To create different lights we operate with to the most important light types: diffuse and specular light.

GLfloat lightDiff0[] = { 1.0, 1.0, 1.0, 1.0 };	// 0 white
GLfloat lightSpec0[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lightDiff1[] = { 1.0, 0.0, 0.0, 1.0 };	// 1 red
GLfloat lightSpec1[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lightDiff2[] = { 0.0, 1.0, 0.0, 1.0 };	// 2 green
GLfloat lightSpec2[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lightDiff3[] = { 0.0, 0.0, 1.0, 1.0 };	// 3 blue
GLfloat lightSpec3[] = { 1.0, 1.0, 1.0, 1.0 };

Diffuse light gives color and is a directional light cast to the object. Diffuse light can be described as the light that has a position in space and comes from a single direction. Specular light is also a directional type of light. It comes from one particular direction. The difference between the two is that specular light reflects off the surface in a sharp and uniform way.

In order to see the light on the screen we need to enable it in our program:

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glEnable(GL_LIGHT2);

Now it’s time to apply the light to our balls. To do that we choose a light position, define which light types we are going to use at each ball and translate it all together to the chosen positions. Here is how it is going to look in openGL:

glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);	// position
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiff0);	// diffuse light
glLightfv(GL_LIGHT0, GL_SPECULAR, lightDiff0); //specular light
glTranslatef(lightPos0[0], lightPos0[1], lightPos0[2]); //translate it all together to position lightPos0
glColor3fv(lightDiff0);  //color
glutSolidSphere(0.1, 6, 6); //ball

After we’ve chosen the light and applied it to our balls we probably want them to move around that big ball in the middle. Since this is an ordinary ball we need to use a combination of cos and sin functions to force the small balls to move around the big one.

Read also: How to draw a robot hand in OpenGL

float x,y,z,len;
x = sin(a/17); y = sin(a/23), z = cos(-a/31); len = sqrt(x*x+y*y+z*z);
GLfloat lightPos0[] = {1.5*x/len, 1.5*y/len, 1.5*z/len, 1.0};
GLfloat lightPos1[] = {sin(a+18), sin(a+24)+cos(a+28), cos(-a+32), 1.0};
GLfloat lightPos2[] = {sin(a+19), sin(a+25)+cos(a+29), cos(-a+33), 1.0};
GLfloat lightPos3[] = {sin(a+20), sin(a+26)+cos(a+30), cos(-a+34), 1.0};

Complete source for this example

GLfloat lightDiff0[] = { 1.0, 1.0, 1.0, 1.0 };	// 0 white
GLfloat lightSpec0[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lightDiff1[] = { 1.0, 0.0, 0.0, 1.0 };	// 1 red
GLfloat lightSpec1[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lightDiff2[] = { 0.0, 1.0, 0.0, 1.0 };	// 2 green
GLfloat lightSpec2[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lightDiff3[] = { 0.0, 0.0, 1.0, 1.0 };	// 3 blue
GLfloat lightSpec3[] = { 1.0, 1.0, 1.0, 1.0 };
float a=0;		// counter

void display(void)
{
	a+=0.1;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	gluLookAt(5,0,5, 0,0,0,	0,1,0);

	glDisable(GL_LIGHTING);		// disable the light while setting it up

	// calculate position of the light
	float x,y,z,len;
	x = sin(a/17); y = sin(a/23), z = cos(-a/31); len = sqrt(x*x+y*y+z*z);
	GLfloat lightPos0[] = {1.5*x/len, 1.5*y/len, 1.5*z/len, 1.0};
	GLfloat lightPos1[] = {sin(a+18), sin(a+24)+cos(a+28), cos(-a+32), 1.0};
	GLfloat lightPos2[] = {sin(a+19), sin(a+25)+cos(a+29), cos(-a+33), 1.0};
	GLfloat lightPos3[] = {sin(a+20), sin(a+26)+cos(a+30), cos(-a+34), 1.0};

	glPushMatrix();	// white
		glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
		glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiff0);
		glLightfv(GL_LIGHT0, GL_SPECULAR, lightDiff0);
		glTranslatef(lightPos0[0], lightPos0[1], lightPos0[2]);
		glColor3fv(lightDiff0); glutSolidSphere(0.1, 6, 6);
	glPopMatrix();

	glPushMatrix(); // red
		glLightfv(GL_LIGHT1, GL_POSITION, lightPos1);
		glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDiff1);
		glLightfv(GL_LIGHT1, GL_SPECULAR, lightSpec1);
		glTranslatef(lightPos1[0], lightPos1[1], lightPos1[2]);
		glColor3fv(lightDiff1); glutSolidSphere(0.1, 6, 6);
	glPopMatrix();

	glPushMatrix(); // green
		glLightfv(GL_LIGHT2, GL_POSITION, lightPos2);
		glLightfv(GL_LIGHT2, GL_DIFFUSE, lightDiff2);
		glLightfv(GL_LIGHT2, GL_SPECULAR, lightSpec2);
		glTranslatef(lightPos2[0], lightPos2[1], lightPos2[2]);
		glColor3fv(lightDiff2); glutSolidSphere(0.1, 6, 6);
	glPopMatrix();

	glPushMatrix(); // blue
		glLightfv(GL_LIGHT3, GL_POSITION, lightPos3);
		glLightfv(GL_LIGHT3, GL_DIFFUSE, lightDiff3);
		glLightfv(GL_LIGHT3, GL_SPECULAR, lightSpec3);
		glTranslatef(lightPos3[0], lightPos3[1], lightPos3[2]);
		glColor3fv(lightDiff3); glutSolidSphere(0.1, 6, 6);
	glPopMatrix();

	glEnable(GL_LIGHTING);		// enable the light when drawing the big ball

	// draw the big ball in the middle
	glPushMatrix();
		glColor3f(1, 1, 0.1);
		glutSolidSphere(1, 16, 16);
	glPopMatrix();
	Sleep(9); glutSwapBuffers();
}
void reshape(int w, int h)
{
	if (h == 0)	h = 1;
	GLdouble ratio = 1.0f * w / h;
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glViewport(0, 0, w, h);
	gluPerspective(45.0, ratio, 0.1, 1000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowSize(640, 480);
	glutCreateWindow("Lys og kuler");
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);

	// enable light
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHT2);

	// set up callbacks
	glutReshapeFunc(reshape);
	glutDisplayFunc(display);
	glutIdleFunc(display);

	// start the program
	glutMainLoop();
}

See Also

Comments

Any comments? Create a new discussion on GitHub.
There used to be an inline comment form here, but it was removed.