open Point
open Vector
type t =
Directional of Point.t * Point.t (* direction, color *)
| Point of Point.t * Point.t (* origin, color *)
| Spot of Point.t * Point.t * Point.t * float * float * Vector.t
(* origin at color cutoff exponent unit(orig-at) *)
let directional dir c = Directional(fudge dir, c)
let point pos c = Point(fudge pos, c)
let spot pos at c cutoff exp =
let pos = Point.fudge pos
and at = Point.fudge at
and cutoff = Misc.fudge cutoff
in
Spot(pos, at, c, cutoff, exp, Vector.normalize(Vector.between at pos))
exception Not_visible
let color_from_light scene pt v n kd ks phong light =
(* Direction towards light source *)
let dir =
match light with
Directional(d, col) -> {dx = -. d.x; dy = -. d.y; dz = -. d.z}
| Point(origin, col) -> Vector.between pt origin
| Spot(origin, _, _, _, _, _) -> Vector.between pt origin in
(* Check that light source is not behind us *)
if Vector.dotproduct dir n <= 0.0 then raise Not_visible;
(* Check that no object blocks the light *)
begin match Intersect.intersect_ray pt dir scene false with
None -> ()
| Some(p, bobj) ->
begin match light with
Directional(_, _) -> raise Not_visible
| _ -> if p < 1.0 then raise Not_visible
end
end;
(* Compute the L and H vectors *)
let l = Vector.normalize dir in
let h = Vector.normalize (Vector.sub l (Vector.normalize v)) in
(* Intensity of light source at object *)
let i =
match light with
Directional(d, col) -> col
| Point(origin, col) ->
(* Apply attenuation factor *)
let att = 100.0 /. (99.0 +. Point.dist2 pt origin) in
{x = col.x *. att; y = col.y *. att; z = col.z *. att}
| Spot(origin, at, col, cutoff, exp, normdir) ->
(* Compute normalized dot product pt - orig and at - orig *)
let dp = Vector.dotproduct l normdir in
(* Angle theta between pt - orig and at - orig is cos theta = dp;
check that it is below cutoff *)
if acos dp >= cutoff then raise Not_visible;
(* Compute attenuation due to direction and attenuation due to
distance *)
let att = (dp ** exp) *. (100.0 /. (99.0 +. Point.dist2 pt origin)) in
(* Apply attenuation factor *)
{x = col.x *. att; y = col.y *. att; z = col.z *. att} in
(* Final contribution *)
let m = kd *. Vector.dotproduct n l +. ks *. (Vector.dotproduct n h) ** phong
in { x = m *. i.x; y = m *. i.y; z = m *. i.z }
let color_from_lights scene pt v norm kd ks phong lights =
let resx = ref 0.0 and resy = ref 0.0 and resz = ref 0.0 in
for i = 0 to Array.length lights - 1 do
try
let c = color_from_light scene pt v norm kd ks phong lights.(i) in
resx := !resx +. c.x;
resy := !resy +. c.y;
resz := !resz +. c.z
with Not_visible ->
()
done;
{x = !resx; y = !resy; z = !resz}