Use option to signal when no object is hit

This commit is contained in:
Samrat Man Singh 2016-03-11 12:06:01 +05:45
parent 1380a1a07f
commit bf8996c953

View file

@ -9,10 +9,12 @@ type sphere = { center: Vec3.vec3;
type hitable = Sphere of sphere type hitable = Sphere of sphere
| World of hitable list | World of hitable list
type hit = { t : float; type hit_rec = { t : float;
p: Vec3.vec3; p: Vec3.vec3;
normal: Vec3.vec3; normal: Vec3.vec3; }
hit: bool }
type hit = hit_rec option
let hit_sphere sphere ray (tmin, tmax) = let hit_sphere sphere ray (tmin, tmax) =
let oc = sub ray.origin sphere.center in let oc = sub ray.origin sphere.center in
@ -21,11 +23,6 @@ let hit_sphere sphere ray (tmin, tmax) =
let c = (dot oc oc) -. (sphere.radius *. sphere.radius) in let c = (dot oc oc) -. (sphere.radius *. sphere.radius) in
let discriminant = b*.b -. a*.c in let discriminant = b*.b -. a*.c in
let no_hit = { t = -1.0;
p = Vec3.of_floats (Float.infinity, Float.infinity, Float.infinity);
normal = Vec3.of_floats (0., 0., 0.);
hit = false } in
if (discriminant > 0.0) if (discriminant > 0.0)
then then
let t = (-.b +. (sqrt discriminant)) /. a in let t = (-.b +. (sqrt discriminant)) /. a in
@ -33,34 +30,33 @@ let hit_sphere sphere ray (tmin, tmax) =
if (t < tmax && t > tmin) if (t < tmax && t > tmin)
then then
let p = Ray.point_at_parameter ray t in let p = Ray.point_at_parameter ray t in
{ t = t; Some { t = t;
p = p; p = p;
normal = unit_vector (sub p sphere.center); normal = unit_vector (sub p sphere.center); }
hit = true }
else else
let t = (-.b -. (sqrt discriminant)) /. a in let t = (-.b -. (sqrt discriminant)) /. a in
if (t < tmax && t > tmin) if (t < tmax && t > tmin)
then then
let p = Ray.point_at_parameter ray t in let p = Ray.point_at_parameter ray t in
{ t = t; Some { t = t;
p = p; p = p;
normal = unit_vector (sub p sphere.center); normal = unit_vector (sub p sphere.center); }
hit = true } else None
else no_hit else None
else no_hit
let rec hit_world world ray (tmin, tmax) = let rec hit_world world ray (tmin, tmax) =
let init_rec = { t = tmax;
p = Vec3.of_floats (-1., -1., -1.);
normal = Vec3.of_floats (-1., -1., -1.);
hit = false; } in
List.fold world List.fold world
~init: init_rec ~init: None
~f: (fun acc h -> ~f: (fun acc h ->
let hit_rec = (hit h ray (tmin, acc.t)) in let prev_rec = match acc with
if (hit_rec.hit) None -> { t = tmax;
then hit_rec p = Vec3.of_floats (-1., -1., -1.);
else acc) normal = Vec3.of_floats (-1., -1., -1.); }
| Some r -> r in
match (hit h ray (tmin, prev_rec.t)) with
Some r -> Some r
| None -> acc)
and hit h ray (tmin, tmax) = and hit h ray (tmin, tmax) =
match h with match h with
Sphere s -> hit_sphere s ray (tmin, tmax) Sphere s -> hit_sphere s ray (tmin, tmax)
@ -72,15 +68,21 @@ let get_color ray =
radius = 0.5 } in radius = 0.5 } in
let sphere2 = Sphere {center = Vec3.of_floats (0., -100.5, -1.); let sphere2 = Sphere {center = Vec3.of_floats (0., -100.5, -1.);
radius = 100.0 } in radius = 100.0 } in
let world = World [sphere1; sphere2] in let world = World [sphere2; sphere1] in
let hit_result = (hit world ray (0., Float.infinity)) in
match (hit world ray (0., Float.infinity)) with
Some hit_result ->
let t = hit_result.t in let t = hit_result.t in
if (hit_result.hit && (t > 0.0)) if (t > 0.0)
then let n = hit_result.normal in then let n = hit_result.normal in
mul 0.5 (Vec3.of_floats (n.x +. 1., n.y +. 1., n.z +. 1.)) mul 0.5 (Vec3.of_floats (n.x +. 1., n.y +. 1., n.z +. 1.))
else let unit_direction = unit_vector ray.dir in else let unit_direction = unit_vector ray.dir in
let t = 0.5 *. (unit_direction.y +. 1.0) in let t = 0.5 *. (unit_direction.y +. 1.0) in
add (mul (1.0 -. t) {x= 1.0; y=1.0; z= 1.0}) (mul t {x= 0.5; y= 0.7; z= 1.0}) add (mul (1.0 -. t) {x= 1.0; y=1.0; z= 1.0}) (mul t {x= 0.5; y= 0.7; z= 1.0})
| None ->
let unit_direction = unit_vector ray.dir in
let t = 0.5 *. (unit_direction.y +. 1.0) in
add (mul (1.0 -. t) {x= 1.0; y=1.0; z= 1.0}) (mul t {x= 0.5; y= 0.7; z= 1.0})
let write_to_file filename = let write_to_file filename =