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:
Now, the specular highlights should look a little more like these:
As I understand, the lighting model (for these diffuse spheres) looks like this:
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.
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