- Diffuse Lighting Fix

If you perform diffuse lighting on a red sphere, the hemisphere where the

light is shining should appear to be a more well-lit red, instead of white

(specular highlights are white). If diffuse lighting is not looking

correct, try adding the color of the material as a multiplicative factor

to the diffuse calculation. You can do this by changing:

Color = summation( Kd * Ci * (Li dot N) )

...to:

Color = summation( Kd * Cm * Ci * (Li dot N) )

Kd is the diffuse coefficient, Cm is the color of the material, Ci is the

color of the light i , Li is the unit light vector to light i, and N is

the unit normal.

- Shadow Ray Floating Point Errors

One issue with computing shadow rays is that you may get a false

intersection hit when you test a shadow ray. When you generate a shadow

ray coming from, say, the surface of a sphere, and you test if the ray

intersects an object, floating point error may result in your code

computing an intersection for the very sphere you started at.

You'll notice this error if see surfaces that should be well-lit, but they

are peppered with black dots of shadow. The floating point error in the

shadow test causes some of the shadow rays to intersect with the sphere

itself even though they shouldn't, which then creates these black dots.

To fix this error, the most robust solution is to actually move the shadow

ray out a little from the point of intersection along the direction of the

ray, to get out of the range of floating point imprecision. For instance,

if your original ray were:

r(t) = P0 + t * dir

...you can transform it to:

r'(t) = P1 + t * dir

...where...

P1 = P0 + EPSILON * dir

EPSILON = a very small, positive float, like 0.001, (a global constant)

This floating point error applies not only to shadow rays, but also to

reflection and refraction rays, which will need to be similarly

moved by EPSILON along their directions.

- Ray Data Structure

Clearing up a point of confusion, the two fields of a ray struct in the

starter code are (point start, point end), which is really a point

followed by a direction. In other words,

point start - a POINT, it is the point that the way starts at, w = 1.0

point end - a VECTOR, it is the direction that the ray is pointing in, w = 0.0

- Correction to raytrace.pdf

In the pseudocode in raytrace.pdf (linked from the Project 4 website), the

4th line on the second page reads:

spec := Ks[j] * intensity(flec) * (r.V)^ns[j];

There are a few things wrong with this line. First, to clarify what (r.V)

is, 'r' should be the unit vector Ri, the reflection of Li (the light

vector for light i) about the normal. 'V' is correct, meaning it is the

unit viewer vector. Also, since Ri exists for each light, we need to sum

it over all lights.

Finally, the multiplcation sign between intensity(flec) and [the dot

product with a power] should instead be an add sign. Since one of these

terms calculatates global reflection color while the other term calculates

local specular highlights and they are independent, we need an add rather

than a multiply.

So, the corrected line should read:

spec := Ks[j] * ( intensity(flec) + summation_i { (Ri.V)^ns[j] } );

Also note that instead of (Ri.V), you can use the half vector dotted with

the normal, (Hi.N). To get the right effects, you may also want to break

the specular coefficient Ks[j] down into two nonequal coefficients, one

multiplying the global reflection ray intensity only and the other

multiplying the sum of the specular highlights only.