|
Lighting in OpenGL
An Introduction |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
glNormal*()
// Normals
static GLfloat normals[][3] = {{ 0.0, 0.0, 1.0}, // front
{ 1.0, 0.0, 0.0}, // right
{ 0.0,-1.0, 0.0}, // bottom
{ 0.0, 0.0,-1.0}, // back
{-1.0, 0.0, 0.0}, // left
{ 0.0, 1.0, 0.0} // top
};
glBegin(GL_POLYGON);
// One normal for all vertices
glNormal3fv(normals[face]);
// One color for all the vertices
glColor4fv(colorPurple);
// The vertices
for (int i = 0; i < 4; i++) {
glVertex3fv(vertices[faces[face][i]]);
}
glEnd();
void glMaterial*(GLenum face, GLenum name, TYPE value)
GLenum is GL_FRONT,
GL_BACK, or GL_FRONT_AND_BACK
GL_AMBIENT, GL_DIFFUSE,
GL_AMBIENT_AND_DIFFUSE, or
GL_SPECULAR
GL_SHININESS
GLfloat
GL_EMISSION
#ifndef edu_jmu_cs_Materials_h
#define edu_jmu_cs_Materials_h
int BRASS = 0;
int BRONZE = 1;
int CHROME = 2;
int COPPER = 3;
int GOLD = 4;
int PEWTER = 5;
int SILVER = 6;
int JADE = 7;
int OBSIDIAN = 8;
int PEARL = 9;
int RUBY = 10;
int TURQUOISE = 11;
int BLACK_PLASTIC = 12;
int BLACK_RUBBER = 13;
int LAST_MATERIAL = 14;
float SPECULAR_EXPONENTS[] =
{
27.897400, // BRASS
25.600000, // BRONZE
76.800003, // CHROME
12.800000, // COPPER
51.200001, // GOLD
09.846150, // PEWTER
51.200001, // SILVER
76.800003, // EMERALD
12.800000, // JADE
38.400002, // OBSIDIAN
11.264000, // PEARL
76.800003, // RUBY
12.800000, // TURQUOISE
32.000000, // BLACK_PLASTIC
10.000000 // BLACK_RUBBER
};
float MATERIAL_COLORS[][3][4] =
{
// BRASS
{
{0.329412, 0.223529, 0.027451, 1.000000}, // Ambient RGBA
{0.780392, 0.568627, 0.113725, 1.000000}, // Diffuse RGBA
{0.992157, 0.941176, 0.807843, 1.000000} // Specular RGBA
},
// BRONZE
{
{0.212500, 0.127500, 0.054000, 1.000000},
{0.714000, 0.428400, 0.181440, 1.000000},
{0.393548, 0.271906, 0.166721, 1.000000}
},
// CHROME
{
{0.250000, 0.250000, 0.250000, 1.000000},
{0.400000, 0.400000, 0.400000, 1.000000},
{0.774597, 0.774597, 0.774597, 1.000000}
},
// COPPER
{
{0.191250, 0.073500, 0.022500, 1.000000},
{0.703800, 0.270480, 0.082800, 1.000000},
{0.256777, 0.137622, 0.086014, 1.000000}
},
// GOLD
{
{0.247250, 0.199500, 0.074500, 1.000000},
{0.751640, 0.606480, 0.226480, 1.000000},
{0.628281, 0.555802, 0.366065, 1.000000}
},
// PEWTER
{
{0.105882, 0.058824, 0.113725, 1.000000},
{0.427451, 0.470588, 0.541176, 1.000000},
{0.333333, 0.333333, 0.521569, 1.000000}
},
// SILVER
{
{0.192250, 0.192250, 0.192250, 1.000000},
{0.507540, 0.507540, 0.507540, 1.000000},
{0.508273, 0.508273, 0.508273, 1.000000}
},
// EMERALD
{
{0.021500, 0.174500, 0.021500, 0.550000},
{0.075680, 0.614240, 0.075680, 0.550000},
{0.633000, 0.727811, 0.633000, 0.550000}
},
// JADE
{
{0.135000, 0.222500, 0.157500, 0.950000},
{0.540000, 0.890000, 0.630000, 0.950000},
{0.316228, 0.316228, 0.316228, 0.950000}
},
// OBSIDIAN
{
{0.053750, 0.050000, 0.066250, 0.820000},
{0.182750, 0.170000, 0.225250, 0.820000},
{0.332741, 0.328634, 0.346435, 0.820000}
},
// PEARL
{
{0.250000, 0.207250, 0.207250, 0.922000},
{1.000000, 0.829000, 0.829000, 0.922000},
{0.296648, 0.296648, 0.296648, 0.922000}
},
// RUBY
{
{0.174500, 0.011750, 0.011750, 0.550000},
{0.614240, 0.041360, 0.041360, 0.550000},
{0.727811, 0.626959, 0.626959, 0.550000}
},
// TURQUOISE
{
{0.100000, 0.187250, 0.174500, 0.800000},
{0.396000, 0.741510, 0.691020, 0.800000},
{0.297254, 0.308290, 0.306678, 0.800000}
},
// BLACK_PLASTIC
{
{0.000000, 0.000000, 0.000000, 1.000000},
{0.010000, 0.010000, 0.010000, 1.000000},
{0.500000, 0.500000, 0.500000, 1.000000}
},
// BLACK_RUBBER
{
{0.020000, 0.020000, 0.020000, 1.000000},
{0.010000, 0.010000, 0.010000, 1.000000},
{0.400000, 0.400000, 0.400000, 1.000000}
}
};
#endif
void glLight*(GLenum light, GLenum name, TYPE value)
light is GL_LIGHT0 ...
GL_LIGHT7
GL_AMBIENT, GL_DIFFUSE, or
GL_SPECULAR
GL_POSITION
GL_CONSTANT_ATTENUATION,
GL_LINEAR_ATTENUATION, or
GL_QUADRATIC_ATTENUATION
GLfloat
GL_SPOT_CUTOFF
GL_SPOT_DIRECTION
GL_SPOT_EXPONENT
GLfloat
void glLightModel*(GLenum name, TYPE value)
GL_LIGHT_MODEL_AMBIENT
GL_LIGHT_MODEL_LOCAL_VIEWER
GL_TRUE for a local viewer
GL_FALSE for a viewer at infinity
GL_LIGHT_MODEL_TWO_SIDE
GL_TRUE to light both sides
or GL_FALSE to light the front
GL_LIGHT_MODEL_COLOR_CONTROL
GL_SINGLE_COLOR or
GL_SEPARATE_SPECULAR_COLORS
glShadeModel(GL_SMOOTH);
// Intensity of ambient light (RGBA)
GLfloat lightingmodelAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightingmodelAmbient);
// Calculation of specular reflection angles (local or infinite viewer?)
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
// Two-sided lighting?
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glEnable(GL_LIGHTING)
void glEnable(GLenum light)
light is GL_LIGHT0 ...
GL_LIGHT7
#include <GL/glut.h>
#include "materials.h"
/**
* \file
* A simple OpenGL application that demonstrates lighting
* a sphere
*
* Click the:
* Left button to cycle through different light positions
* Middle button to cycle through different materials
* Right button to translate the sphere to the right
*
* Note: Double buffering is not used so the screen may flicker
*
* Compile under MinGW with:
* g++ -o sphere -Wall sphere.c -lglut -lGL -lGLU
*
* @author Prof. David Bernstein, James Madison University
*/
int window;
static GLint axis = 0;
static GLfloat shininess = 50.0;
static GLfloat light0Position[] = { 2.0, 0.0, 0.0, 1.0 };
//Colors
static GLfloat colorBlue[] = { 0.0, 0.0, 1.0, 1.0 };
static GLfloat colorGold[] = { 0.761, 0.631, 0.302, 1.000 }; // JMU Gold
static GLfloat colorGreen[] = { 0.0, 1.0, 0.0, 1.0 };
static GLfloat colorPurple[] = { 0.271, 0.000, 0.518, 1.000 }; // JMU Purple
static GLfloat colorRed[] = { 1.0, 0.0, 0.0, 1.0 };
static GLfloat colorWhite[] = { 1.0, 1.0, 1.0, 1.0 };
static int material = 0;
/**
* Create a window.
*
* @param title The title
* @param width The width (in pixels)
* @param height The height (in pixels)
* @param x The x position
* @param y The y position
* @return The window id
*/
int createWindow(char* title, int width, int height, int x, int y) {
int id;
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(width, height);
glutInitWindowPosition(x, y);
id = glutCreateWindow(title);
return id;
}
/**
* Perform OpenGL initializations.
*/
void init() {
glClearColor(colorGold[0], colorGold[1], colorGold[2], colorGold[3]);
// The color of the material for specular reflection
glMaterialfv(GL_FRONT, GL_SPECULAR, colorWhite);
// The exponent of the specular reflection model
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
glShadeModel(GL_SMOOTH);
// Intensity of ambient light (RGBA)
GLfloat lightingmodelAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightingmodelAmbient);
// Calculation of specular reflection angles (local or infinite viewer?)
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
// Two-sided lighting?
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glLightfv(GL_LIGHT0, GL_POSITION, light0Position);
glLightfv(GL_LIGHT0, GL_DIFFUSE, colorWhite);
glLightfv(GL_LIGHT0, GL_SPECULAR, colorWhite);
glEnable(GL_LIGHTING); // Enable lighting
glEnable(GL_LIGHT0); // Enable light number 0
glEnable(GL_DEPTH_TEST); // Enable depth buffering
}
/**
* The mouse callback (i.e., the function that is called
* each time a mouse button is pressed or released).
*
* @param button The button (e.g., GLUT_LEFT_BUTTON)
* @param state The state (e.g., GLUT_UP or GLUT_DOWN)
* @param x The x-position of the mouse
* @param y The y-position of the mouse
*/
void mouseClicked(int button, int state, int x, int y) {
if (state == GLUT_DOWN) {
if (button == GLUT_LEFT_BUTTON) {
light0Position[axis] = 0.0;
axis = (axis + 1) % 3;
light0Position[axis] = 2.0;
glLightfv(GL_LIGHT0, GL_POSITION, light0Position);
} else if (button == GLUT_RIGHT_BUTTON) {
material = (material + 1) % LAST_MATERIAL;
glMaterialfv(GL_FRONT, GL_AMBIENT, MATERIAL_COLORS[material][0]);
glMaterialfv(GL_FRONT, GL_DIFFUSE, MATERIAL_COLORS[material][1]);
glMaterialfv(GL_FRONT, GL_SPECULAR, MATERIAL_COLORS[material][2]);
glMaterialf(GL_FRONT, GL_SHININESS, SPECULAR_EXPONENTS[material]);
} else if (button == GLUT_MIDDLE_BUTTON) {
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.10, 0.0, 0.0);
}
}
glutPostRedisplay();
}
/**
* Display/render the OpenGL window
*/
void display() {
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Create the content
glutSolidSphere(1.0, 20, 16);
//glutSolidTeapot(1.0);
glFlush();
}
/**
* The reshape callback
*
* @param w The width
* @param h The height
*/
void reshape(int w, int h) {
GLfloat aspect;
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h) {
aspect = (GLfloat) h / (GLfloat) w;
glOrtho(-1.5, 1.5, -1.5 * aspect, 1.5 * aspect, -10.0, 10.0);
} else {
aspect = (GLfloat) w / (GLfloat) h;
glOrtho(-1.5 * aspect, 1.5 * aspect, -1.5, 1.5, -10.0, 10.0);
}
}
/**
* The entry point of the application.
*
* This function contains calls to GLUT.
*
* @param argc The number of command line arguments
* @param argv The array of command line arguments
* @return A status code
*/
int main(int argc, char** argv) {
glutInit(&argc, argv);
window = createWindow("Sphere Lighting", 640, 480, 0, 0);
// Callbacks
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouseClicked);
init();
glutMainLoop();
}
#include <stdio.h>
#include <GL/glut.h>
#include <math.h>
/**
* \file
* A simple OpenGL application that demonstrates lighting
* a solid model
*
* Click the:
* Left button to cycle through different light positions
*
* Press the:
* x or X key to rotate around the x-axis
* y or Y key to rotate around the y-axis
* z or Z key to rotate around the z-axis
*
*
* Compile under Linux with:
* g++ -o solidmodel -Wall solidmodel.c -lglut -lGL -lGLU
*
* @author Prof. David Bernstein, James Madison University
*/
int window;
static GLint axis = 0;
static GLfloat shininess = 50.0;
static GLfloat light0Position[4];
static GLfloat colorWhite[] = { 1.0, 1.0, 1.0, 1.0 };
static int count;
static GLfloat *x, *y, *z;
static GLfloat *nx, *ny, *nz;
static GLfloat *r, *g, *b;
static GLfloat color[3];
static GLfloat max[3], min[3];
static GLfloat left, right, bottom, top, znear, zfar;
static GLfloat theta[] = { 0.0, 0.0, 0.0 };
/**
* Create a window.
*
* @param title The title
* @param width The width (in pixels)
* @param height The height (in pixels)
* @param x The x position
* @param y The y position
* @return The window id
*/
int createWindow(char* title, int width, int height, int x, int y) {
int id;
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(width, height);
glutInitWindowPosition(x, y);
id = glutCreateWindow(title);
return id;
}
/**
* Perform OpenGL initializations.
*/
void init() {
glClearColor(colorWhite[0], colorWhite[1], colorWhite[2], colorWhite[3]);
glMaterialfv(GL_FRONT, GL_SPECULAR, colorWhite);
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
glShadeModel(GL_SMOOTH);
GLfloat lightingmodelAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightingmodelAmbient);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_FALSE);
glLightfv(GL_LIGHT0, GL_POSITION, light0Position);
glLightfv(GL_LIGHT0, GL_DIFFUSE, colorWhite);
glLightfv(GL_LIGHT0, GL_SPECULAR, colorWhite);
glEnable(GL_LIGHTING); // Enable lighting
glEnable(GL_LIGHT0); // Enable light number 0
glEnable(GL_DEPTH_TEST); // Enable depth buffering
}
/**
* The mouse callback (i.e., the function that is called
* each time a mouse button is pressed or released).
*
* @param button The button (e.g., GLUT_LEFT_BUTTON)
* @param state The state (e.g., GLUT_UP or GLUT_DOWN)
* @param x The x-position of the mouse
* @param y The y-position of the mouse
*/
void mouseClicked(int button, int state, int x, int y) {
if (state == GLUT_DOWN) {
if (button == GLUT_LEFT_BUTTON) {
light0Position[axis] = 0.0;
axis = (axis + 1) % 3;
light0Position[axis] = max[axis];
glLightfv(GL_LIGHT0, GL_POSITION, light0Position);
}
}
glutPostRedisplay();
}
/**
* Display/render the OpenGL window.
*/
void display() {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Center
glTranslatef(-(left + right) / 2.0, -(top + bottom) / 2.0,
-(znear + zfar) / 2.0);
// Rotate
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);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
for (int i = 0; i < count; i++) {
int k;
k = 3 * i;
// Define the material properties for this triangle
color[0] = r[i]; color[1] = g[i]; color[2] = b[i];
glMaterialfv(GL_FRONT, GL_AMBIENT, color);
glMaterialfv(GL_FRONT, GL_DIFFUSE, color);
glMaterialfv(GL_FRONT, GL_SPECULAR, color);
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
// Define the vertices and normals for this triangle
glNormal3f(nx[k], ny[k], nz[k]);
glVertex3f(x[k], y[k], z[k]);
glNormal3f(nx[k + 1], ny[k + 1], nz[k + 1]);
glVertex3f(x[k + 1], y[k + 1], z[k + 1]);
glNormal3f(nx[k + 2], ny[k + 2], nz[k + 2]);
glVertex3f(x[k + 2], y[k + 2], z[k + 2]);
}
glEnd();
glFlush();
glutSwapBuffers();
}
/**
* The reshape callback
*
* @param width The width
* @param height The height
*/
void reshape(int width, int height) {
GLfloat x, y, z;
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
x = fmax(abs(left), abs(right));
y = fmax(abs(top), abs(bottom));
z = fmax(abs(znear), abs(zfar));
glOrtho(-2 * x, 2 * x, -2 * y, 2 * y, -2 * z, 2 * z);
}
/**
* Read the data from a file.
*
* @param fileName The name of the file
*/
void readData(const char* fileName) {
char s[80];
FILE *in;
float v[3];
int color;
for (int i = 0; i < 3; i++) {
min[i] = 99999999.;
max[i] = -99999999.;
}
in = fopen(fileName, "r");
// Read the number of triangles
fscanf(in, "%d", &count);
// Initialize the arrays
// NOTE: This memory is never returned to the free store!
r = new GLfloat[count];
g = new GLfloat[count];
b = new GLfloat[count];
x = new GLfloat[count * 3];
y = new GLfloat[count * 3];
z = new GLfloat[count * 3];
nx = new GLfloat[count * 3];
ny = new GLfloat[count * 3];
nz = new GLfloat[count * 3];
for (int k = 0; k < count * 3; k++) {
x[k] = 0.0;
y[k] = 0.0;
z[k] = 0.0;
nx[k] = 0.0;
ny[k] = 0.0;
nz[k] = 0.0;
}
// Read the triangles
for (int k = 0; k < count; k++) {
// Triangle indicator
fscanf(in, "%s", s);
// Front Color
fscanf(in, "%d", &color);
r[k] = (float) color / 255.0;
fscanf(in, "%d", &color);
g[k] = (float) color / 255.0;
fscanf(in, "%d", &color);
b[k] = (float) color / 255.0;
// Back Color (which is ignored)
fscanf(in, "%d", &color);
fscanf(in, "%d", &color);
fscanf(in, "%d", &color);
// The vertices and normals
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
fscanf(in, "%f", &(v[j])); // Vertex
if (v[j] < min[j])
min[j] = v[j];
if (v[j] > max[j])
max[j] = v[j];
}
x[3 * k + i] = v[0];
y[3 * k + i] = v[1];
z[3 * k + i] = v[2];
fscanf(in, "%f", &(nx[3 * k + i]));
fscanf(in, "%f", &(ny[3 * k + i]));
fscanf(in, "%f", &(nz[3 * k + i]));
}
}
left = min[0];
right = max[0];
bottom = min[1];
top = max[1];
znear = min[2];
zfar = max[2];
light0Position[0] = max[0];
light0Position[1] = max[1];
light0Position[2] = max[2];
light0Position[3] = 1.0;
}
/**
* The keyboard callback
*
* @param key The key that was pressed
* @param x The x-position of the mouse when the key was pressed
* @param y The y-position of the mouse when the key was pressed
*/
void keyboardFunc(unsigned char key, int x, int y) {
if (key == 'x')
theta[0] -= 10.00;
else if (key == 'X')
theta[0] += 10.00;
else if (key == 'y')
theta[1] -= 10.00;
else if (key == 'Y')
theta[1] += 10.00;
else if (key == 'z')
theta[2] -= 10.00;
else if (key == 'Z')
theta[2] += 10.00;
else if (key == ' ')
theta[0] = theta[1] = theta[2] = 0.0;
// Request a callback to the DisplayFunc
glutPostRedisplay();
}
/**
* The entry point of the application.
*
* This function contains calls to GLUT.
*
* @param argc The number of command line arguments
* @param argv The array of command line arguments
* @return A status code
*/
int main(int argc, char** argv) {
glutInit(&argc, argv);
if (argc == 1)
readData("church.txt");
else
readData(argv[1]);
window = createWindow("Solid Model Lighting", 640, 640, 0, 0);
// Callbacks
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouseClicked);
glutKeyboardFunc(keyboardFunc);
init();
glutMainLoop();
}