(***********************************************************************) (* *) (* JoCamls'R Us - a not so simple ray tracer in JoCaml *) (* *) (* Luc Maranget, projet Moscova, INRIA Rocquencourt *) (* *) (* Copyright 2007 Institut National de Recherche en Informatique et *) (* en Automatique. This file is distributed under the terms of the *) (* GNU Public License version 2, http://www.gnu.org/licenses/gpl.txt *) (* *) (* Important: based upon the ray tracer of the Camls'R'Us team *) (* written at the occasion of the ICFP programming contest 2000 *) (* Copyright 2000 Institut National de Recherche en Informatique et *) (* en Automatique. *) (* *) (* *) (***********************************************************************) open Point open Vector open Light 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}