Firstly, if your getRayDirection()
is doing what it says it is, it's producing a direction, and not a gaze point, so you should not be subtracting the ray origin from it, which is a point.
(Although directions and points are both represented by vectors, it does not make sense
to add a point to a direction)
Also, you are normalising L1
and then taking its magnitude and dividing each of its components by that magnitude, to produce UnitVector
, which you then call normalize
on again. This is unnecessary: The magnitude of L1
after the first normalization is 1, you're normalizing the same vector 3 times, just use L1
.
The last issue, is that of clamping. The variable you call Factor
is the value cos(th)
where th
is the angle between the direction of light and the normal. But cos(th)
has a range of [1,-1]
and you want a range of only [0,1]
, so you must clamp Factor
to that range:
Factor = max(0, min( NormalIntersect.dotProduct(UnitVector), 1));
(And remove the min
calls in your production of color
).
This clamping is necessary for faces whose normals are facing away from the light, which will have negative cos(th)
values. The angle between their normal and the direction of light are greater than pi/2
. Intuitively, they should appear as dark as possible with respect to the light in question, so we clamp them to 0).
Here's my final version of the code, which should work. I'm going to work on the assumption that you have scale(float)
and operator +(const TVector &)
etc defined on your TVector
class, because they will quite plainly make your life easier. Also, for brevity, I'm going to call NormalIntersect
, just normal
:
TVector
intersect = ray.getRayOrigin() + ray.getRayDirection().scale(t),
normal = (intersect - position).normalize(),
L1 = (light.GetPosition() - intersect).normalize();
float
diffuse = max(0, min(normal.dotProduct(L1), 1)),
kd = 0.1,
ka = 0.9;
Color pixelFinalColor = color.scale(kd * diffuse + ka);