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(); }