GLART week 4: Light and Material

Lighting is both an art and science and there are many techniques to create convincing light in computer graphics. The OpenGL lighting system is designed to approximate light behavior in a relatively simple and efficient fashion. It is good at rendering light in real-time, for example in a computer game. Other more expensive approaches to light rendering that you find in Maya or 3DS Max, such as ray tracing, require higher end hardware or are meant for use in still images or video output. OpenGL lighting does not calculate reflections and scattering of light and does not produce shadows. There are ways to approximate more subtle lighting effects using textures, shadow mapping, and shaders. OpenGL light properties are very flexible, and may not be immediately intuitive, but, like brush and pigment, they provide a wide range of options for creating the illusion of light and reflection in a scene. Light works with Materials. Light has meaning only when there is a surface to reflect the light and OpenGL has functions to define the properties of a surface: what color the surface is and how much or how little it reflects light. These "material properties" describe the surface. Once you enable lighting, OpenGL uses default material values until you specify your own settings. Assigment: Light a sphere Reading: Redbook pages 173-210 "Chapter 5: Lighting" Examples: Calculate a Normal Light one triangle Light a curved surface Smooth the normals Simple Light Example Move a light (and glow) Review: Create a custom matrix (see week 2 for matrix math links) Images: Examples of light in painting See also: nate robbins light tutorial: Vector Mathematics examples NOTES: ================================================================= Normals ---------------------------- For OpenGL to calculate light on a surface, it needs to know which way the surface is facing. The surface "normal" is a vector perpendicular to the surface. Given three points (the vertices of a triangle) we can calculate a normal for that triangle (see Vector3D.getNormal()). The glNormal() command tells OpenGL what normal to use for all the following glVertex() calls. If you call glNormal() once for each triangle in a sphere, each triangle will appear to be flat and distinct from the others (faceted). To create a smooth continuous surface, you need to assign normals to each vertex, and average the normals across the triangles. For instance, if a vertex is on the border between two triangles, you would average the normals for the two triangles and assign that average to the vertex. It's good to understand normals, though you usually won't have to calculate them yourself. In most cases the models you load (from Maya or 3DS Max) will have normals already calculated for you. You may need to calculate normals yourself if you're generating your own geometry in your code. Normals should have a length of 1. Call glEnable(GL.GL_NORMALIZE) to tell OpenGL to force all normals to have a length of 1. If normals are different lengths then lighting will fall unevenly across the surface. Light ---------------------------- There are two main components to lighting: Light color Surface color (aka. the material color) Light properties define how light propagates from a source. There are three components of light color: Diffuse light -- the light rays coming directly from source Specular light -- the light reflected off a shiny surface Ambient light -- the light scattered off the environment Usually all three colors are similar. A red light will illuminate a surface with red, the reflection will be red, and the scattered light in the environment will be a dim red. Material properties define how a surface reflects light. They do this by defining color values much the same way that lights do. A material has color value for diffuse (direct) light, ambient (scattered) light, and specular (reflected) light, but these values define how the components of light are **reflected** off the material surface. The incoming light colors are combined with the corresponding material color and the resulting color is what we see on screen. These material values have meaning only in relation to the light source(s). For instance if your material reflects ambient light (ie. the material AMBIENT setting has a color value), it will still appear as black if there is no AMBIENT light coming from the light source. Similarly, the diffuse material color may be yellow but it will appear greenish if the diffuse light color is green. The material specular value is usually white, gray or black, because it has no hue of it's own, it is reflecting the hue of the light that is shining on it. Think of this color value as defining the percentage of light that will be reflected. There is an additional material setting, shininess, that defines the size of the surface reflection. A Simple Approach to Lighting: ------------------------------ There is much room for fudging in the lighting system. You can invent very un-intuitive light conditions that have no relationship to actual light conditions in the real world. Here is a simple way to think of light and material. Diffuse is the direct light color, and specular is the reflected light color. In reality these two are usually the same (a green light will cast greenish light on a surface, and the reflection will be green). Ambient describes how the light is scattered by the environment, which isn't really a property of the light at all, it's a property of the environment. For example, sunlight directly striking an object appears white/yellow, but sunlight scattered in the atmosphere takes on a bluish hue. In outer space there would be no ambient light because there is no atmosphere to scatter the sunlight. For simplicity, OpenGL folds this property into the light. Materials describe how these different light components (diffuse, ambient. specular), reflect off a surface. In reality a material reflects the same way whether it's reflecting direct or scattered light. How to simplify light and material: To define a light: set diffuse to the color you want the light to be set specular equal to diffuse set ambient to 1/4 of diffuse. To define a material: set diffuse to the color you want the material to be, set specular to a gray (white is brightest reflection, black is no reflection) set ambient to 1/4 of diffuse, Some things to remember: --------------------------------------- * Once lighting is enabled, the vertex colors are ignored. OpenGL calculates it's own color values for each vertex, based on the color of the light and the degree of illumination. * Normals are critical to correct lighting. The vertex normals tell OpenGL what angle a plane is at. Based on the angle of the plane with respect to the light and eye positions, OpenGL calculates the reflected light. * Normal lengths matter! They should all be length of 1, or light will fall unevenly. The easiest way to do this is to enable GL_NORMALIZE. The Sphere object provides normals for us, as will many model file formats. * Distance matters! When a positional light comes close to a surface, the angle of light becomes very acute and the vertices get very different light values. This will look like rippling on the surface. * A light can be positional (light radiates from a point,ie. a light bulb) or directional (light rays are parallel and illuminate entire scene evenly, ie. from the sun). The fourth position value sets positional/directional. * Remember, once you enable GL_LIGHTING there is a default light and default material in effect. You can change material properties, but there will always be some sort of material in effect. * Spheres may be buggy at some sizes. Watch out for complex shapes at very low sizes (.2, .3, etc.). * Lights are points in the space like vertices and can be transformed just like vertices. Use glLight(GL.GL_POSITION...) after glTranslate() glRotate() to change light position. * Emissive material property typically overrides diffuse, ambient, specular (unless the glow is very faint). Emissive light is not radiant, doesn't cast light on other objects. You use another light source to do that. Functions: glEnable(GL_LIGHTING) turn on lighting glEnable(GL_LIGHT1) turn on a single light source. There are seven light sources in OpenGL. glLight(GL_LIGHT1, GL_DIFFUSE, RGB_color_values) define the color of a light source. The RGB values define the color, and are passed into the function as a FloatBuffer. There are four color values we can define for a light: GL_DIFFUSE, GL_SPECUlAR, GL_AMBIENT, and GL_EMISSIVE. glLight(GL_LIGHT1, GL_POSITION, XYZ_Position_values) define the light position. We pass four values. The first three are XYZ. If the fourth value is a 1 then the XYZ values are treated as a position of the light source (positional light). Positional lights are a point light source that will fade if the light position is very far from the surface (ie. a light bulb). If the fourth value is a 0 then the the XYZ values describe the direction of the light (directional light). Directional light shines at the same intensity and from the same direction on all surfaces (ie. the sun). glLightModel(GL_LIGHT_MODEL_AMBIENT, RGB_color_values) define overall properties of the lighting environment, such as Ambient light for the entire scene. glNormal3f(x,y,z) defines the normal value for the following vertices. used inside a glBegin() ... glEnd() block affects the glVertex() commands that follow