How to render a complex 3D scene
• Typical rendering loop for a 3D environment1. Initialize modelview matrix (glIdentity)
2. Change viewpoint (gluLookat or glTranslate,glRotate)
3. Save the current modelview matrix (glPushMatrix)
4. Place stuff on the scene (glTranslate,glRotate)
5. Draw stuff
6. Restore the modelview matrix from matrix stack
(glPopMatrix)Repeat 3~6
Example
void RenderScene(void){ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, 1.0f, 1.0f, 1000.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 200.0, 200.0, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); glViewport(0, 0, windowWidth, windowHeight); glEnable(GL_DEPTH_TEST); // Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT);
// Draw objects in the scene DrawModels();
// Flush drawing commands glutSwapBuffers();
}
void DrawModels(void){ // Draw plane that the objects rest on glColor3f(0.0f, 0.0f, 0.90f); // Blue glNormal3f(0.0f, 1.0f, 0.0f); glBegin(GL_QUADS); glVertex3f(-100.0f, -25.0f, -100.0f); glVertex3f(-100.0f, -25.0f, 100.0f); glVertex3f(100.0f, -25.0f, 100.0f); glVertex3f(100.0f, -25.0f, -100.0f); glEnd();
// Draw red cube glColor3f(1.0f, 0.0f, 0.0f); glutSolidCube(48.0f);
// Draw green sphere glColor3f(0.0f, 1.0f, 0.0f); glPushMatrix(); glTranslatef(-60.0f, 0.0f, 0.0f); glutSolidSphere(25.0f, 50, 50); glPopMatrix();
// Draw yellow cone glColor3f(1.0f, 1.0f, 0.0f); glPushMatrix(); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); glTranslatef(60.0f, 0.0f, -24.0f); glutSolidCone(25.0f, 50.0f, 50, 50); glPopMatrix();
// Draw magenta torus glColor3f(1.0f, 0.0f, 1.0f); glPushMatrix(); glTranslatef(0.0f, 0.0f, 60.0f); glutSolidTorus(8.0f, 16.0f, 50, 50); glPopMatrix();
// Draw cyan octahedron glColor3f(0.0f, 1.0f, 1.0f); glPushMatrix(); glTranslatef(0.0f, 0.0f, -60.0f); glScalef(25.0f, 25.0f, 25.0f); glutSolidOctahedron(); glPopMatrix();}
Example (cont’d)#include <gl/glut.h>
int windowWidth = 600;int windowHeight = 600;
void DrawModels(void);void RenderScene(void);void ChangeSize(int w, int h);
int main(int argc, char* argv[]){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);glutInitWindowSize(windowWidth,windowHeight);glutCreateWindow("Example");glutReshapeFunc(ChangeSize);glutDisplayFunc(RenderScene);glutMainLoop();return 0;
}
void ChangeSize(int w, int h){
windowWidth = w;windowHeight = h;
}
Immediate mode
• glBegin() ~ glEnd()– It requires many thousands of very small, potentially
expensive operations to submit a batch of geometry.• Primitive batches are assembled by using individual
glVertex/glNormal/glTexCoord calls.
– That’s a good bit of work for the CPU to perform to draw a single triangle. But, the graphics hardware sitting idle waiting on the CPU to assemble and submit geometry batches in case of drawing a complex 3D scene.
Example#include <math.h>#include <time.h>#include <stdlib.h>#include <gl/glut.h> #define PI 3.141592
typedef struct _Vector3D{
float x;float y;float z;
} Vector3D;
static GLfloat angle, velocity = 5;static Vector3D pos = {0.0, -20.0, 0.0};void DrawCube(CubeData *pData);void ChangeSize(GLsizei width, GLsizei height){
GLfloat fAspect = (GLfloat)width/(GLfloat)height;GLfloat nRange = height/4.0;if(height == 0)height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);glLoadIdentity();
gluPerspective(45.0f, fAspect, 1.0, 4000.0);
glMatrixMode(GL_MODELVIEW);glLoadIdentity();
}
void SpecialKeys(int key, int x, int y){
if(key == GLUT_KEY_UP){
pos.x -= (velocity*sin(angle*PI/180.0));pos.z += (velocity*cos(angle*PI/180.0));
}if(key == GLUT_KEY_DOWN){
pos.x += (velocity*sin(angle*PI/180.0));pos.z -= (velocity*cos(angle*PI/180.0));
}
if(key == GLUT_KEY_LEFT)angle -= 5.0f;if(key == GLUT_KEY_RIGHT)angle += 5.0f;
angle = (GLfloat)((const int)angle % 360);
glutPostRedisplay();}
void SetupRC(){
glClearColor(0.0, 0.0, 0.0, 0.0);glEnable(GL_DEPTH_TEST);
}
void RenderScene(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();glRotatef(angle, 0.0f, 1.0f, 0.0f);glTranslatef(pos.x, pos.y, pos.z);
glutSwapBuffers();}
int main(int argc, char *argv[]){
glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);glutInitWindowSize(600, 600);glutCreateWindow("Example");glutReshapeFunc(ChangeSize);glutSpecialFunc(SpecialKeys);glutDisplayFunc(RenderScene);SetupRC();
glutMainLoop();
return 0;
}
Declaration and initialization cube data structure
#define MAX_CUBE 10000typedef struct _CubeData{
Vector3D pos;Vector3D angle;Vector3D color;
} CubeData;CubeData cData[MAX_CUBE];
• Add following codes to SetupRC function
srand((unsigned char)time(NULL));for (int i = 0 ; i < MAX_CUBE ; i++ ){
cData[i].pos.x = rand() % 8000 - 4000;cData[i].pos.z = rand() % 8000 - 4000;cData[i].angle.x = rand() % 360;cData[i].angle.y = rand() % 360;cData[i].angle.z = rand() % 360;cData[i].color.x = (float)(rand() % 101) / 100.0;cData[i].color.y = (float)(rand() % 101) / 100.0;cData[i].color.z = (float)(rand() % 101) / 100.0;
}
Generate cube data randomly
3d position, orientation and color of a cube
Drawing functionvoid DrawCube(CubeData *pData){
glMatrixMode(GL_MODELVIEW);glTranslatef(pData->pos.x, 0.0, pData->pos.z);glRotatef(pData->angle.x, 1.0, 0.0, 0.0);glRotatef(pData->angle.y, 0.0, 1.0, 0.0);glRotatef(pData->angle.z, 0.0, 0.0, 1.0);
glColor3f(pData->color.x, pData->color.y, pData->color.z);glBegin(GL_QUADS);glVertex3f(10.0,10.0,10.0);glVertex3f(10.0,-10.0,10.0);glVertex3f(-10.0,-10.0,10.0);glVertex3f(-10.0,10.0,10.0);
glVertex3f(10.0,10.0,-10.0);glVertex3f(10.0,-10.0,-10.0);glVertex3f(-10.0,-10.0,-10.0);glVertex3f(-10.0,10.0,-10.0);
glVertex3f(10.0,10.0,-10.0);glVertex3f(10.0,10.0,10.0);glVertex3f(-10.0,10.0,10.0);glVertex3f(-10.0,10.0,-10.0);
glVertex3f(10.0,-10.0,-10.0);glVertex3f(10.0,-10.0,10.0);glVertex3f(-10.0,-10.0,10.0);glVertex3f(-10.0,-10.0,-10.0);
glVertex3f(10.0,10.0,10.0);glVertex3f(10.0,10.0,-10.0);glVertex3f(10.0,-10.0,-10.0);glVertex3f(10.0,-10.0,10.0);
glVertex3f(-10.0,10.0,10.0);glVertex3f(-10.0,10.0,-10.0);glVertex3f(-10.0,-10.0,-10.0);glVertex3f(-10.0,-10.0,10.0);glEnd();
}
• insert following codes to RenderScene function (before glutSwapBuffers call).
for ( int i = 0 ; i < MAX_CUBE ; i++ )
{
glPushMatrix();
DrawCube(cData+i);
glPopMatrix();
}
Display List
• A precompiled set of OpenGL commands for rapid execution.– Optimization of the immediate mode.
– Can avoid repetitive rendering tasks.• such as trigonometric calculations for drawing sphere, torus…
– Only for static objects.
Display List
• void glNewList (GLuint list, GLenum mode)– Display lists are created with glNewList.
– All subsequent commands are placed in the display list, in the order issued, until glEndList is called.
– list : Specifies the display-list name.
– mode• GL_COMPILE
• GL_COMPILE_AND_EXECUTE
Display List
• Gluint glGenLists (GLsizei range)– generates a contiguous set of empty display lists.– Range
• The number of contiguous empty display lists to be generated.– It returns an integer n such that range contiguous empty display lists, named n, n +
1, . . ., n + (range - 1), are created.
• void glDeleteLists (GLuint list, GLsizei range)– deletes a contiguous group of display lists.
• void glCallList (GLuint list)– executes a display list.
• void glCallLists (GLsizei n, GLenum type, const GLvoid *lists)
– execute a list of display lists.– n : the number of display lists.– type : the type of value in lists (GL_UNSIGNED_INT, GL_UNSIGNED_BYTE)– lists : the address of an array of name offsets in the display list.
Example - Display list• Declare global variable which is used for
display list name.– GLuint cubeDList;
• Modify SetupRC function and Renderscene function as following.
20
Vertex Buffer Objects
•Store vertex data (vertex, normal vector, color etc.)
•Stored on graphics hardware for non-immediate rendering.
•Substantial performance gains over immediate mode rendering.
Client and Server State
Application
Buffer Objects
GL Server
GL Client
size
type
stride
pointer
buffer
ARRAY_BUFFER_ARB
size
type
stride
pointer
buffer
size
type
stride
pointer
buffer
size
type
stride
pointer
buffer
● Buffer objects are server state● Vertex arrays parameters are client state
Memory + State
Per-Array Buffer Specification
VertexPointer(size, type, stride, *pointer);
Size
type
stride
pointer
bufferARRAY_BUFFER_ARB
offset
25
Angel: Interactive Computer Graphics 5E © Addison-Wesley 2009
Creating Vertex Buffer Objects
Creating a VBO requires 3 steps:
1. Generate a new buffer object with glGenBuffersARB().
2. Bind the buffer object with glBindBufferARB().
3. Copy vertex data to the buffer object with glBufferDataARB().
26
C Example
/* Initialise VBO - do only once, at start of program *//* Create a variable to hold the VBO identifier */unsigned int triangleVBO; /* Vertices of a triangle (counter-clockwise winding) */float data[] = {1.0, 0.0, 1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 1.0}; /* Create a new VBO and use the variable id to store the VBO id */glGenBuffers(1, &triangleVBO); /* Make the new VBO active */glBindBuffer(GL_ARRAY_BUFFER, triangleVBO); /* Upload vertex data to the video device */glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
27
/* Draw Triangle from VBO - do each time window, view point or data changes *//* Establish its 3 coordinates per vertex with zero stride in this array; necessary here */glVertexPointer(3, GL_FLOAT, 0, NULL); /* Make the new VBO active. Repeat here incase changed since initialisation */glBindBuffer(GL_ARRAY_BUFFER, triangleVBO); /* Establish array contains vertices (not normals, colours, texture coords etc) */glEnableClientState(GL_VERTEX_ARRAY); /* Actually draw the triangle, giving the number of vertices provided */glDrawArrays(GL_TRIANGLES, 0, sizeof(data) / sizeof(float) / 3); /* Force display to be drawn now */glFlush();
28
Updating Vertex Buffer Objects
• Use glBufferDataARB() or glBufferSubDataARB() to overwrite data.
• glMapBufferARB() in order to map the buffer object into client's memory. Use glUnmapBufferARB() to unmap.
// bind then map the VBOglBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);float* ptr = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
// if the pointer is valid(mapped), update VBOif(ptr){ updateMyVBO(ptr, ...); // modify buffer data glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); // unmap it}
29
Vertex Array Object
•Despite the name, they do not store vertices.
•Used to store openGL state attributes.•Contain a reference pointer to a vertex buffer object, but this is not required for all cases (e.g. glDrawArrays).
30
Angel: Interactive Computer Graphics 5E © Addison-Wesley 2009
Pixel Buffer Objects
•Similar concept, allows pixel data to be transferred to gfx card without cpu (through direct memory access).
•Can perform asynchronous DMA transfer between a PBO and a texture object.
•Can modify a portion of the buffer object or the entire buffer by using glMapBufferARB() and glUnmapBufferARB().
31
Angel: Interactive Computer Graphics 5E © Addison-Wesley 2009
// "index" is used to copy pixels from a PBO to a texture object// "nextIndex" is used to update pixels in the other PBOindex = (index + 1) % 2;if(pboMode == 1) nextIndex = index; // with 1 PBOelse if(pboMode == 2) nextIndex = (index + 1) % 2; // with 2 PBOs // bind the texture and PBOglBindTexture(GL_TEXTURE_2D, textureId);glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[index]);
// copy pixels from PBO to texture object. Use offset instead of pointer.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, 0);
// bind PBO to update texture sourceglBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[nextIndex]);
Manipulating Textures
32
// Note: See BellowglBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_DRAW_ARB);
// map the buffer object into client's memoryGLubyte* ptr = (GLubyte*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);if(ptr){ // update data directly on the mapped buffer updatePixels(ptr, DATA_SIZE); glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB); // release the mapped buffer}
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
Manipulating Textures
// Note that glMapBufferARB() causes sync issue.// If GPU is working with this buffer, glMapBufferARB() will wait(stall)// until GPU to finish its job. To avoid waiting (idle), you can call// first glBufferDataARB() with NULL pointer before glMapBufferARB().// If you do that, the previous data in PBO will be discarded and// glMapBufferARB() returns a new allocated pointer immediately// even if GPU is still working with the previous data.
33
// "index" is used to read pixels from framebuffer to a PBO// "nextIndex" is used to update pixels in the other PBOindex = (index + 1) % 2;nextIndex = (index + 1) % 2;
// set the target framebuffer to readglReadBuffer(GL_FRONT);
// read pixels from framebuffer to PBO glReadPixels() returns immediately.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);glReadPixels(0, 0, WIDTH, HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, 0);
// map the PBO to process its data by CPUglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);GLubyte* ptr = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);if(ptr){ processPixels(ptr, ...); glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);}
// back to conventional pixel operationglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
Modifying the Front Buffer
Lighting and shading
• A sphere drawn by using glColor (left) does not look like a real sphere (right).
• Light-material interactions cause each point to have a different color or shade.
• Need to consider – Light sources– Material properties– Location of viewer– Surface orientation
Blinn-Phong reflection model
• A simple reflection model which can be computed rapidly.
• The default reflection model used in OpenGL.
• It has three components– Diffuse
– Specular
– Ambient
I =kd Id l · n + ks Is (h · n )+ ka Ia
Light intensity
Surface reflectance
Specular exponent
Normal vector
• Normal vectors which provide direction of the surface are essential for correct lighting calculation.
• Diffuse and specular components depend on the normal vector.
– void glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);– void glNormal3fv (const GLfloat *v);
– All surface normal vectors must eventually be converted to unit vectors to make lighting calculations correctly be done.
• glEnable(GL_NORMALIZE); • Normal vectors of any length specified with glNormal are normalized automatically after
transformation.• This approach does, however, have performance penalties on some implementations.
Enabling the lighting
• glEnable(GL_LIGHTING);
• Setting global ambient illumination– void glLightModelfv (GLenum pname, const
GLfloat *params);• pname : GL_LIGHT_MODEL_AMBIENT
• params : Specify intensity of global ambient illumination, which has four values.
Setting up light sources– glEnable(GL_LIGHT0);
• At least 8 light sources are supported.(GL_LIGHT0 ~ GL_LIGHT8)
– Setting light source parameters
• void glLightfv (GLenum light, GLenum pname, const GLfloat *params);– light : The identifier of a light. (GL_LIGHT0 ~ GL_LIGHT8)
– pname : A light source parameter for light.» GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_POSITION
– params : Specifies a pointer to the value or values that parameter pname of light source light will be set to.
» Intensity of the light has four values.
» Position of the light has four values. If the last value in the array is 0.0, it indicates that the light is an infinite distance away along the vector specified by this array.
Example code - lightsource#include <gl/glut.h>
static GLfloat xRot = 0.0f;static GLfloat yRot = 0.0f;static GLfloat xRotLight = 0.0f;static GLfloat yRotLight = 0.0f;static int width, height;GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };GLfloat lightPos[] = { -50.f, 50.0f, 100.0f, 1.0f };bool bMoveLightSource = false;
void SetProjection(){
GLfloat fAspect = (GLfloat)width/(GLfloat)height;GLfloat nRange = height/4.0;if(height == 0)height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);glLoadIdentity();
gluPerspective(60.0f, fAspect, 1.0, 400.0);
glMatrixMode(GL_MODELVIEW);glLoadIdentity();
}
void ChangeSize(GLsizei w, GLsizei h){
width = w;height = h;SetProjection();
}
void SpecialKeys(int key, int x, int y){
if (!bMoveLightSource){if(key == GLUT_KEY_UP) xRot-= 5.0f;if(key == GLUT_KEY_DOWN) xRot += 5.0f;if(key == GLUT_KEY_LEFT) yRot -= 5.0f;if(key == GLUT_KEY_RIGHT) yRot += 5.0f;xRot = (GLfloat)((const int)xRot % 360);yRot = (GLfloat)((const int)yRot % 360);}else{if(key == GLUT_KEY_UP) xRotLight-= 5.0f;if(key == GLUT_KEY_DOWN) xRotLight += 5.0f;if(key == GLUT_KEY_LEFT) yRotLight -= 5.0f;if(key == GLUT_KEY_RIGHT) yRotLight += 5.0f;xRotLight = (GLfloat)((const int)xRotLight % 360);yRotLight = (GLfloat)((const int)yRotLight % 360);
}
if (key == GLUT_KEY_F1){bMoveLightSource = !bMoveLightSource;}glutPostRedisplay();
}
Example code - lightsourcevoid RenderScene(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();glTranslatef(0.0f, 0.0f, -300.0f);glRotatef(xRot, 1.0f, 0.0f, 0.0f);glRotatef(yRot, 0.0f, 1.0f, 0.0f);glPushMatrix();
glRotatef(xRotLight, 1.0f, 0.0f, 0.0f);glRotatef(yRotLight, 0.0f, 1.0f, 0.0f);glLightfv(GL_LIGHT0,GL_POSITION,lightPos);glPopMatrix();
// glColor will be ignored.glColor3f(1.0, 0.0, 0.0);glutSolidTeapot(100.0);glPopMatrix();glutSwapBuffers();
}
void SetupRC(){
glEnable(GL_DEPTH_TEST);glCullFace(GL_BACK);glEnable(GL_LIGHTING);glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);glEnable(GL_LIGHT0);
}
int main(int argc, char *argv[]){
glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);glutInitWindowSize(600, 600);glutCreateWindow("Light source");glutReshapeFunc(ChangeSize);glutSpecialFunc(SpecialKeys);glutDisplayFunc(RenderScene);
SetupRC();glutMainLoop();
return 0;}
Result - lightsource• Although color of the object was set to red by using glColor3f
function, the object was colored gray.• When light is enabled, the color of an object depends on its
material properties such as reflectance.
Material properties
• void glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);– face :
• GL_FRONT, GL_BACK, GL_FRONT_AND_BACK– pname :
• GL_AMBIENT, GL_DIFFUSE, GL_EMISSION, GL_SPECULAR,GL_AMBIENT_AND_DIFFUSE
– params : Specifies a pointer to the value or values that pname will be set to.• Reflectivity has four values
Example code – material properties
• Source code is based on lightsource example.• Add a global variable for reflectance.
– GLfloat material[] = { 0.75f, 0.0, 0.0, 1.0f };• Modify RenderScene() function as following.
void RenderScene(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();glTranslatef(0.0f, 0.0f, -300.0f);glRotatef(xRot, 1.0f, 0.0f, 0.0f);glRotatef(yRot, 0.0f, 1.0f, 0.0f);glPushMatrix();
glRotatef(xRotLight, 1.0f, 0.0f, 0.0f);glRotatef(yRotLight, 0.0f, 1.0f, 0.0f);glLightfv(GL_LIGHT0,GL_POSITION,lightPos);glPopMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, material);glutSolidTeapot(100.0);glPopMatrix();glutSwapBuffers();
}
Color tracking• Current color which specified by glColor function is used 1as material
reflectance.• glEnable(GL_COLOR_MATERIAL);
• void glColorMaterial (GLenum face, GLenum mode);– face
• GL_FRONT, GL_BACK, GL_FRONT_AND_BACK– mode
• GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_AMBIENT_AND_DIFFUSE
Example code – color tracking• Source code is based on material properties example.• Add following statements to SetupRC() function.
– glEnable(GL_COLOR_MATERIAL);– glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
• Modify RenderScene() function as following.void RenderScene(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();glTranslatef(0.0f, 0.0f, -300.0f);glRotatef(xRot, 1.0f, 0.0f, 0.0f);glRotatef(yRot, 0.0f, 1.0f, 0.0f);glPushMatrix();
glRotatef(xRotLight, 1.0f, 0.0f, 0.0f);glRotatef(yRotLight, 0.0f, 1.0f, 0.0f);glLightfv(GL_LIGHT0,GL_POSITION,lightPos);glPopMatrix();
glColor3f(0.0, 1.0, 0.0);glutSolidTeapot(100.0);glPopMatrix();glutSwapBuffers();
}
Specular exponent
• The specular exponent of the material specifies how small and focused the specular highlight is.– α in specular term ks Is (h · n )
• void glMaterialf (GLenum face, GLenum pname, const GLfloat param);
• pname :– GL_SHINESS : specular exponent
• parans :– Specify specular exponent value in the range of [0, 128]. If the value is small,
the object will have a large wide specular highlight and appear less shinny.
Example code – specular highlight• Source code is based on color tracking example.• Add following global variable for specluar reflectance.
– GLfloat materialSpecular[] = { 1.0f, 1.0f, 1.0f, 1.0f };• Modify RenderScene() function as following.
void RenderScene(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();glTranslatef(0.0f, 0.0f, -300.0f);glRotatef(xRot, 1.0f, 0.0f, 0.0f);glRotatef(yRot, 0.0f, 1.0f, 0.0f);glPushMatrix();
glRotatef(xRotLight, 1.0f, 0.0f, 0.0f);glRotatef(yRotLight, 0.0f, 1.0f, 0.0f);glLightfv(GL_LIGHT0,GL_POSITION,lightPos);glPopMatrix();
glMaterialfv(GL_FRONT, GL_SPECULAR,materialSpecular);glMaterialf(GL_FRONT,GL_SHININESS,100);glColor3f(0.0, 1.0, 0.0);glutSolidTeapot(100.0);glPopMatrix();glutSwapBuffers();
}
Result - specular highlight• GL_SHININESS is 100.• Narrow and focused specular
highlight is produced (red circle).
• GL_SHININESS is 1.• Wide and unfocused specular
highlight is produced.
Example code• In case of rendering user-defined model instead
of predefined model in GLUT, normal vectors must be specified explicitly.
• Add following function.
void DrawCube(){
glBegin(GL_QUADS);glNormal3f(0.0, 0.0, 1.0);glVertex3f(50.0,50.0,50.0); glVertex3f(50.0,-50.0,50.0);glVertex3f(-50.0,-50.0,50.0); glVertex3f(-50.0,50.0,50.0);
glNormal3f(0.0, 0.0, -1.0);glVertex3f(50.0,50.0,-50.0); glVertex3f(-50.0,50.0,-50.0);glVertex3f(-50.0,-50.0,-50.0); glVertex3f(50.0,-50.0,-50.0);
glNormal3f(0.0, 1.0, 0.0);glVertex3f(50.0,50.0,-50.0); glVertex3f(50.0,50.0,50.0);glVertex3f(-50.0,50.0,50.0); glVertex3f(-50.0,50.0,-50.0);
glNormal3f(0.0, -1.0, 0.0);glVertex3f(50.0,-50.0,-50.0); glVertex3f(-50.0,-50.0,-50.0);glVertex3f(-50.0,-50.0,50.0); glVertex3f(50.0,-50.0,50.0);
glNormal3f(1.0, 0.0, 0.0);glVertex3f(50.0,50.0,50.0);glVertex3f(50.0,50.0,-50.0); glVertex3f(50.0,-50.0,-50.0); glVertex3f(50.0,-50.0,50.0);
glNormal3f(-1.0, 0.0, 0.0);glVertex3f(-50.0,50.0,50.0); glVertex3f(-50.0,-50.0,50.0);glVertex3f(-50.0,-50.0,-50.0); glVertex3f(-50.0,50.0,-50.0);glEnd();
}
• Call DrawCube() function instead of glutSolidTeapot() call in RenderScene() function.
Spot light
• To apply spotlight, you should specify direction of light source and cut-off angle.– glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,angle);
• Specify cut-off angle in degrees.
– glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,spotDir);
Example code - spotlight
• Source code is based on color tracking example.• Add following global variable for direction of the spotlight.
– GLfloat spotDir[] = { -lightPos[0],-lightPos[1],-lightPos[2], 1.0 };
• Add following statement to SetupRC() function– glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,60.0f);
• Remove the statement associated with specifying ambient component of light from SetupRC function.
• Add following statement to RenderScene() function (near the statement specifying light direction).– glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,spotDir);