DUE: Tuesday, 27 October, in class
Create a 3D environment with intentionally mismatched depth cues.
Include multiple 3D objects. Have the objects move in 3 dimensions, or have the camera move, or both.
Use multiple depth cues, and make some of them conflict. The conflict should be clear, but perhaps not always immediately obvious.
To calculate how much light reflects off of a surface, OpenGL needs to know which direction the surface is facing.
The surface orientation combined with the direction of the light determines the intensity of the diffuse component of lighting.
The surface orientation, light direction, and direction to the viewer determines the specular component.
The orientation of a surface is defined by a normal - a vector perpendicular to the surface.
A normal should be a unit vector - its length should be 1.
Normals in OpenGL are given with the glNormal function.
Lighting calculations use a normal at each vertex drawn;
you can provide a normal with each vertex, or fewer.
glBegin(GL_TRIANGLES) glNormal3f(0, 1, 0) glVertex3f(-1, 0, 0) glNormal3f(0, 1, 0) glVertex3f(1, 0, 0) glNormal3f(0, 1, 0) glVertex3f(0, 0, 2) glEnd()
Examples: normal.py ring-normals.py cube.py
Often you will have 3D polygonal data for an object, but need to generate normal vectors for it, in order to light it.
To compute normals from polygonal vertex data, use the cross product.
The cross product produces a new vector that is perpendicular to the two multiplied vectors. If the two vectors are edges of a polygon, then the cross product will give you a normal vector for the polygon (you will need to normalize its length to be 1.0, however).
Normally, local light sources shine equally in all directions.
Using spotlight options, you can have a light shine in a particular direction.
A spotlight's beam is a cone starting from the light position and pointing in the spotlight direction (GL_SPOT_DIRECTION).
The angle of the cone is defined by the GL_SPOT_CUTOFF value.
GL_SPOT_EXPONENT makes the brightness of the spotlight fall off toward the edges.
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direction) glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, angle) glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, exponent)
All lighting calculations are done only at the vertices.
Spotlights, like specular highlights, will not work well with large polygons.
The geometry must be finely tesselated for a good spotlight effect.
In the real world, the amount of illumination from a light source decreases the farther away you are from it.
By default, OpenGL lighting is the same, no matter how far you are from a light source.
Attenuation simulates the falloff of light with distance.
OpenGL attenuation uses a formula with 3 adjustable coefficients, so that you can vary light realistically, or semi-realistically:
1 brightness = ----------------------- Kc + Kl * d + Kq * d^2
These coefficients are controlled by the following calls:
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, Kc); glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, Kl); glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, Kq);
Some example results:
Kc, Kl, Kq | d = 0 | d=0.5 | d=1 | d=10 | d=100 |
---|---|---|---|---|---|
1, 0, 0 | 1 | 1 | 1 | 1 | 1 |
1, 0.1, 0 | 1 | 0.95 | 0.91 | 0.5 | 0.09 |
1, 0, 0.1 | 1 | 0.98 | 0.91 | 0.09 | 0.001 |
0.1, 0.1, 0 | 10 | 6.67 | 5 | 0.91 | 0.1 |
Two-sided lighting affects how the backs of polygons are rendered.
It is enabled with glLightModel:
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)
A separate material can be specified for the backs of polygons:
glMaterialfv(GL_BACK, GL_DIFFUSE, [1, 1, 1, 1])
The front of a polygon is the side where the vertices appear in counter-clockwise order.
Front | Back |
---|---|
![]() | ![]() |
When two-sided lighting is enabled:
if front side of polygon faces camera: use GL_FRONT material use normal as given else if back side faces camera: use GL_BACK material reverse normal
When two-sided lighting is not enabled, the back of a polygon is illuminated exactly the same as the front - both sides will show the same color.
Fog is a useful effect for realistic large-scale scenes.
It provides an additional depth cue for distant objects - aerial perspective.
It can also be used to hide the edges of a 3D world.
OpenGL fog mixes the color of a fragment with the color of the fog. The degree of mixing is a function of the distance from the camera to the fragment.
finalColor = (1-f) * polyColor + f * fogColor
Example:
glEnable(GL_FOG) glFogi(GL_FOG_MODE, GL_LINEAR) glFogfv(GL_FOG_COLOR, [1, 1, 1, 1]) glFogf(GL_FOG_START, 5.0) glFogf(GL_FOG_END, 40.0)
There are three different fog modes: