Diffuse Illumination • Diffuse illumination is associated with specific light sources but is reflected uniformly in all directions. A white sheet of paper has a high degree of diffuse reflectivity. It reflects light but it also scatters it so that you cannot see the reflection of other objects when looking at the paper. Here is an example of an image with 3 light sources positioned around a sphere: Diffuse Illumination • To model diffuse reflectivity requires the presence of one or more light sources. The first type of light source that we will consider is the point light source. This idealized light source emits light uniformly in all directions. It may be located on either side of the virtual screen but is itself not visible. Diffuse Illumination • The lights will be managed in a way analogous to the visible objects, but will reside on a separate list pointed to by the “lightList” pointer in the scene_t class. class scene_t { public: scene_t(ifstream &infile); int getindex(char *token, char *table[]); void loadScene(ifstream &infile); void dumpScene(); window_t *getWindow(); image_t *getPicture(); /** Lists of objects in the virtual world **/ list_t *sobjList; /* scene objects list list_t *lightList; /* "Lights" list private: int magic; window_t *window; image_t *picture; }; /* magic number /* Window data /* output image */ */ */ */ */ Properties of point light sources • The pointlight_t class holds the location and color intensity of a point light. class pointlight_t : public entity_t { public: pointlight_t(ifstream &infile, const string & objtype); void load(ifstream &infile, const string & attr); myvector getcenter(); mycolor getcolor(); double getbrightness(); void dump(); myvector processLight (scene_t *scene, entity_t *ent, hitinfo_t *hit); private: myvector center; mycolor color; double brightness; }; Properties of point light sources • The color of the point light is specified by the color field. The brightness value indicates how bright the light is. • The r, g, b color intensities of the light can be computed as an intensity_t by multiplying each component of the light’s color by the light’s brightness. • The effect of a light on the color of a pixel that is illuminated by a light is the component-wise product of the light’s intensity as computed above and the diffuse reflectivity of the visible object. Properties of point light sources • In a ray traced scene consisting of a single plane and a single light, it is not possible to determine from the image whether a red material is being illuminated by a white light or a white material is being illuminated by a red light! • Furthermore, if a pure red light illuminates a pure green sphere, the result is purely invisible! This effect is counter to our experience because in the “real scene,” monochromatic lights and objects with pure monochromatic reflectivity are not commonly encountered. Specifying a light in a model description file • In the model description language an example of specifying a blue light is: pointlight name bluelight ; color 255 200 100 ; brightness 6 center 0 4 -3 ; ; • The attributes of a point light are the color and brightness values of the light and the coordinates of the center of the light. Diffuse Illumination • A constructor and appropriate load (), dump(), and getter methods will need to be added to the ray tracer to process the characteristics of a light as specified in the SDL file. • These methods should be placed in the module pointlight.cpp Determining diffuse illumination for a pixel • Diffuse illumination should not be computed directly in the rayTrace() function. The procedure is sufficiently complicated that it should be implemented in a separate module that we will call lighting.cpp. It will contain a function called lighting() that will be called by the rayTrace() function. Determining diffuse illumination for a pixel /**/ /* This function traces a single ray and returns the composite */ /* intensity of the light it encounters. It is recursive and */ /* so the start of the ray cannot be assumed to be the viewpt */ myvector rayTrace(scene_t *scene, point_t base, vector_t dir, double total_dist, entity_t *self) { use closest() to determine closest object if nothing hit return intensity values of 0 (black) add distance from base to closest object to total_dist set intensity to the color of closest object times the ambient light of the scene Add the diffuse light of the object at the hit point to the intensity divide intensity by 255 divide intensity by total_distance return intensity } Determining diffuse illumination for a pixel Important notes: • The ambient light is a property of the object as a whole. • The diffuse light is a function of the specific hit point. • The contribution of all lights that are visible from the hit point must be summed. Computing the diffuse reflectivity of an object • A function having the following prototype provides a useful front end for the diffuse computation. It should be called from rayTrace() as shown in the pseudo code on the previous slide. intensity_t lighting( scene_t *scene, /* pointer to scene structure */ entity_t *ent, /* pointer to scene object just hit */ hitinfo_t *hit) /* pointer to scene object’s hitinfo */ { set total_illumination triple to zeros for all lights on the light list { add return value from processLight(…) to total_illumination } return total_illumination } Computing the diffuse reflectivity of an object • • Since there may be other types of lights than just point lights that this procedure might process, this procedure should be placed in the separate module lighting.cpp. We use idealized point light sources which are themselves invisible, but do emit illumination. Thus lights themselves will not be visible in the scene but the effect of the light will appear. Determining if a point light illuminates the hit point The processLight() function performs this portion of the algorithm. intensity_t processLight( scene _t *scene, /* pointer to scene’s entity_t */ entity_t *ent, /* the current scene object */ hitinfo_t *hit) /* pointer to scene object’s hitinfo data */ { if the object hit occludes itself from the light source return 0 triple call closest(...) with a ray starting at the center of the light and pointing in the direction of the hit point if the object hit by this call is not the original object, //some other // object occludes light return 0 intensity compute and return illumination intensity } Determining if a point light illuminates the hit point • Determining if a light is occluded, and if not, the contribution this light makes to the brightness and color of a given pixel is described in the following sections. This procedure should be placed in the pointlight.cpp module. Testing for occlusion • The diagram below illustrates the ways in which objects may occlude lights. The small yellow spheres represent lights and the large blue ones visible objects. Testing for occlusion We will assume convex objects. An object is self-occluding if the angle between the surface normal and a vector from the hit point toward the light is larger than 90 degrees. In this case the cos(θ) would be negative. Recall that the dot product of two unit vectors computes the cosine of the angle between them. In the illustration above cos(θ) would be positive since is less than 90 degrees, while cos(θ') would be negative and the light source to the right of the object would be self-occluded. Testing for occlusion • A simple test for this condition is that an object is not self-occluding if the dot product of a unit vector from the hit point to that light with the unitized surface normal is positive. • To see if a light is occluded by another object, a ray can be fired from the center of the light towards the hit point. If the ray hits the original object then the light is not occluded. Note this is the case with the red vector in the illustration. If the ray hits a different object then the light is occluded. This is the case with the orange ray. Testing for occlusion • We can use closest() to determine if the ray hits the original object. • The base of the ray is the coordinates of the center of the light • The direction vector is a unit vector pointing in the direction from the center of the light to the hit point (note this is a vector pointing in the OPPOSITE direction than the vector used to determine if the light was self-occluded, e.g. the purple vector). • For the red vector the “ent” pointer parameter and the entity pointer returned by the call to closest(), starting from the center of the light, would match. • For the orange vector the “ent” parameter and the entity pointer returned by closest() would not match since the ray hit another object. Computing the illumination • If a light does illuminate the hit point, its effect must be added to the pixel intensity of the current pixel. The effect of the light is determined by the light’s color, the light’s distance from the hit point, the angle of the light to the hit point, and the diffuse reflectivity of the object itself. Computing the illumination • The red, green and blue components of the effect of the light can be computed as follows: result.x = diffuse.x * intensity.x * cos(θ) / dist_from_pointlight_to_hitpoint result.y = diffuse.y * intensity.y * cos(θ) / dist_from_pointlight_to_hitpoint result.z = diffuse.z * intensity.z * cos(θ) / dist_from_pointlight_to_hitpoint • The above computation assumes that diffuse contains the object’s “diffuse”. The color intensities of the light are computed as an intensity_t by multiplying each component of the light’s color by the light’s brightness. • Note: remember that “cos(θ)” is just the dot product of the unit normal and the unit vector pointing from the hit point to the center of the light (you don’t actually call cos()).