A vector is a direction and magnitude (length). Vectors are used to represent many different things - for example, object motion or relative locations of objects. In 3D, vectors are used extensively in lighting.
We normally describe a vector as a pair of (X, Y) values (in 2 dimensions), or a triplet of (X, Y, Z) values (in 3 dimensions) - (vx, vy, vz) represents a vector that points vx units in the direction of the X axis, vy units in the direction of the Y axis, and vz units in the direction of the Z axis.
e.g., (2, 0, 0) is a vector pointing in the direction of the X axis, 2 units long. (1, 1, 0) is a vector pointing at a 45 degree angle between the X and Y axes, 1.414 units long.
The magnitude of a vector (x,y,z) is its Euclidean length - the square root of vx2 + vy2 + vz2.
Two vectors can be combined by adding their corresponding components
together.
i.e. (vx, vy, vz) +
(wx, wy, wz) is
(vx+wx, vy+wy, vz+wz
).
Or, written more expansively:
| vx | | wx | | vx + wx | | vy | + | wy | = | vy + wy | | vz | | wz | | vz + wz |
The result is a vector that is equivalent to sticking the vector W onto the end of vector V, and creating a new vector from the beginning of V to the end of W.
A vector can be multiplied by a single number (a "scalar") to change its length without changing its direction.
| vx | | s * vx | s * | vy | = | s * vy | | vz | | s * vz |
The dot product of two vectors is an operation defined as:
| x0 | | x1 | | y0 | * | y1 | = x0*x1 + y0*y1 + z0*z1 | z0 | | z1 |The result is a single number, which is equal to the product of the lengths of the two vectors and the cosine of the angle between them.
It can tell us how much two vectors point in the same direction - it is maximum when they point in exactly the same direction, and it's 0 when they're at right angles.
The cross product is a function of two vectors that will produce a new vector perpendicular to both. The length of the cross product is equal to the area of the parallelogram formed by the two vectors.
The formula for the cross product of two vectors A & B is:
[ ( Ay Bz - Az By ), ( Az Bx - Ax Bz ), ( Ax By - Ay Bx ) ]
The Python equivalent is:
def crossProduct(A,B): return [ A[1] * B[2] - A[2] * B[1], A[2] * B[0] - A[0] * B[2], A[0] * B[1] - A[1] * B[0] ]
The direction of the cross product is determined by the right-hand rule applied from vector A to vector B (so if you multiply them in the reverse order, the result will point the opposite direction).
Lighting provides very significant cues to the 3 dimensional shape of objects.
Lighting in computer graphics attempts to simulate the behavior of light
in the real world.
Real-time lighting involves significant simplifications.
To make OpenGL use lighting calculations when drawing objects, enable GL_LIGHTING:
glEnable(GL_LIGHTING)
You must also turn on at least one light source:
glEnable(GL_LIGHT0)
Example: drawcow.py
Simulated lighting involves three major components:
Light source attributes are set by glLight.
A light source has a position and a color.
The intensity of the light is simply the intensity of the color.
glEnable(GL_LIGHT0) glLightfv(GL_LIGHT0, GL_POSITION, [0, 1, 0, 0]) glLightfv(GL_LIGHT0, GL_DIFFUSE, [1, 1, 1, 1])
Lights can be infinite (a.k.a. directional) or local
All rays from an infinite light source come in the same direction.
Rays from a local light source come from a particular point in space.
The 4th value in the light source's position controls this feature:
0 = infinite light
1 = local light
# Light comes from above glLightfv(GL_LIGHT0, GL_POSITION, [0, 1, 0, 0]) # Light comes from point (0,1,0) glLightfv(GL_LIGHT1, GL_POSITION, [0, 1, 0, 1])
A light source's position is affected by the current transformation.
Lights should be defined after the camera transformation, in order to define them in "world" coordinates.
They can also be moved with transformations, just like an object.
# Make local light come from position (5, 0, 7) glPushMatrix() glTranslatef(5, 0, 7) glLightfv(GL_LIGHT0, GL_POSITION, [0, 0, 0, 1]) glPopMatrix()
You can enable multiple simultaneous lights.
The lights are named GL_LIGHT0, GL_LIGHT1, ...
At least 8 light sources are allowed - more may be available.
glEnable(GL_LIGHT1) glLightfv(GL_LIGHT1, GL_POSITION, [-1, 1, 2, 0])
More lights = more computations, and potentially slower rendering
Material properties define how a surface reflects light.
Basically, they represent the surface color.
When lighting is active, glColor is ignored; the material is used instead.
Material properties are set using glMaterial.
blue = [0.1, 0.4, 1, 1] glMaterialfv(GL_FRONT, GL_DIFFUSE, blue)
Light sources can have a color & intensity.
The default is full white.
blue = [0.1, 0.4, 1, 1] glLightfv(GL_LIGHT0, GL_DIFFUSE, blue)
The color of a light defines how much red, green, and blue light is shining
on an object.
The color of a material defines how much red, green, and blue light it reflects.
The final color we see is the combination of the two - corresponding components are multiplied together.
The basic lighting effect is diffuse lighting.
The intensity of diffuse lighting depends on the orientation
of the surface relative to the light source.
Diffuse light is reflected equally in all directions.
Specularity is light that is more-or-less directly
reflected off the surface to the camera.
Its intensity depends on the orientation of the surface relative to
camera, as well as to the light source.
Ambient light comes from no particular direction.
It reflects equally in all directions
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 intensity is computed from the dot product of the surface normal and the light direction.
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()
Example: ring-normals.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).
Specularity produces shiny highlights on surfaces.
It involves 3 attributes: the specular color and the shininess of the material, and the specular color of the light source.
glLightfv(GL_LIGHT0, GL_SPECULAR, [1, 1, 1, 1]) glMaterialfv(GL_FRONT, GL_SPECULAR, [1, 1, 1, 1]) glMaterialf(GL_FRONT, GL_SHININESS, 50)
A higher GL_SHININESS value produces smaller highlights.
To disable specularity, set the specular color to black ([0,0,0,0])
Ambient light simulates indirect lighting.
It is basically a constant level of lighting that's added to a surface's color, regardless of orientation.
The ambient lighting effect is the product of the light source's ambient color and the material's ambient color.
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.1, 0.1, 0.1, 1]) glMaterialfv(GL_FRONT, GL_AMBIENT, [1, 1, 1, 1])
There is also a global source of ambient light, controlled by glLightModel
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,[.1, .1, .1, 1])
Additional lighting features in OpenGL are:
Shaders are pieces of custom code that execute on the GPU itself, allowing rendering techniques not part of basic OpenGL
Current graphics cards support:
OpenGL shaders are written in a C-like language called GLSL