2
votes

I am having some trouble getting the lighting model correct for my spheres. Specifically, I can't get the specular highlights for spheres correct. Here is what I am seeing when I raytrace spheres:
Wrong specular highlights

Now, the specular highlights should look a little more like these:
Correct specular highlights

As I understand, the lighting model (for these diffuse spheres) looks like this:
Lighting model

Where cr is the color of the sphere, ca is the ambient component of light, cl is the color of the light, n is the normal at the point of intersection on the sphere, l is the direction of the light, cp is the color of the specular highlight, e is eye/Look From, r is the reflection vector off the surface of the sphere, and p in the exponent refers to the phong constant/exponent (how tight/loose the lightlight is).

Here is my process:

public Color calculateIlluminationModel(Vector normal, Scene scene)
{
    //c = cr * ca + cr * cl * max(0, n \dot l)) + cl * cp * max(0, e \dot r)^p
    Vector lightSourceColor = getColorVector(scene.getLight().getLightColor()); //cl
    Vector diffuseReflectanceColor = getColorVector(getMaterialColor()); //cr
    Vector ambientColor = getColorVector(scene.getLight().getAmbientLightColor()); //ca
    Vector specularHighlightColor = getColorVector(getSpecularHighlight()); //cp
    Vector directionToLight = scene.getLight().getDirectionToLight(); //l
    Vector reflectionVector = normal.multiply(2).multiply(normal.crossProduct(directionToLight)).subtract(directionToLight); //r = 2n(n \dot l) - l

    Vector ambientTerm = diffuseReflectanceColor.multiply(ambientColor);
    double angleBetweenLightAndNormal = directionToLight.dotProduct(normal);
    Vector diffuseTerm = diffuseReflectanceColor.multiply(lightSourceColor).multiply(Math.max(0, angleBetweenLightAndNormal));
    Vector phongTerm = lightSourceColor.multiply(specularHighlightColor).multiply(Math.pow(Math.max(0, scene.getCameraSettings().getLookFrom().dotProduct(reflectionVector)), (double) getPhongConstant()));
    return getVectorColor(ambientTerm.add(diffuseTerm).add(phongTerm));
}

Note that in this case, the eye component for the phong term is the camera's look from, which is (0, 0, 1), and the direction to the light is (1, 0, 0).

Any ideas why my specular highlights are on the top of the spheres instead of facing the direction of the light?

Let me know if I let out any important details that you need to help me out.

2
Why is your camera look-from always (0, 0, 1)? Shouldn't it vary based on which pixel you're currently drawing?Daniel A. Thompson
My understanding was that the eye/origin of the ray doesn't change, just the direction of the ray.Cache Staheli

2 Answers

1
votes

Reflection vector should be calculated based on surface normal and incoming ray direction, not on light direction as you do now.

1
votes

The issue is with this line:

Vector reflectionVector = normal.multiply(2).multiply(normal.crossProduct(directionToLight)).subtract(directionToLight); //r = 2n(n \dot l) - l

Instead of taking the dot product between the normal and the direction to the light, you are instead taking normal.crossProduct(directionToLight), the cross production, which would give you a vector perpendicular to the one you want, giving you the error you are seeing above.

So instead, you should have

Vector reflectionVector = normal.multiply(2).multiply(normal.dotProduct(directionToLight)).subtract(directionToLight); //r = 2n(n \dot l) - l