From bf8996c9530a6a1857c35f226f6ba2041f1ba1cc Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Fri, 11 Mar 2016 12:06:01 +0545 Subject: [PATCH] Use `option` to signal when no object is hit --- src/raytracer.ml | 74 +++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/raytracer.ml b/src/raytracer.ml index ca4d2013..80da2b25 100644 --- a/src/raytracer.ml +++ b/src/raytracer.ml @@ -9,10 +9,12 @@ type sphere = { center: Vec3.vec3; type hitable = Sphere of sphere | World of hitable list -type hit = { t : float; - p: Vec3.vec3; - normal: Vec3.vec3; - hit: bool } +type hit_rec = { t : float; + p: Vec3.vec3; + normal: Vec3.vec3; } + +type hit = hit_rec option + let hit_sphere sphere ray (tmin, tmax) = 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 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) then let t = (-.b +. (sqrt discriminant)) /. a in @@ -33,34 +30,33 @@ let hit_sphere sphere ray (tmin, tmax) = if (t < tmax && t > tmin) then let p = Ray.point_at_parameter ray t in - { t = t; - p = p; - normal = unit_vector (sub p sphere.center); - hit = true } + Some { t = t; + p = p; + normal = unit_vector (sub p sphere.center); } else let t = (-.b -. (sqrt discriminant)) /. a in if (t < tmax && t > tmin) then let p = Ray.point_at_parameter ray t in - { t = t; - p = p; - normal = unit_vector (sub p sphere.center); - hit = true } - else no_hit - else no_hit + Some { t = t; + p = p; + normal = unit_vector (sub p sphere.center); } + else None + else None 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 - ~init: init_rec - ~f: (fun acc h -> - let hit_rec = (hit h ray (tmin, acc.t)) in - if (hit_rec.hit) - then hit_rec - else acc) + ~init: None + ~f: (fun acc h -> + let prev_rec = match acc with + None -> { t = tmax; + p = Vec3.of_floats (-1., -1., -1.); + 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) = match h with Sphere s -> hit_sphere s ray (tmin, tmax) @@ -72,13 +68,19 @@ let get_color ray = radius = 0.5 } in let sphere2 = Sphere {center = Vec3.of_floats (0., -100.5, -1.); radius = 100.0 } in - let world = World [sphere1; sphere2] in - let hit_result = (hit world ray (0., Float.infinity)) in - let t = hit_result.t in - if (hit_result.hit && (t > 0.0)) - then let n = hit_result.normal in - mul 0.5 (Vec3.of_floats (n.x +. 1., n.y +. 1., n.z +. 1.)) - else let unit_direction = unit_vector ray.dir in + let world = World [sphere2; sphere1] in + + match (hit world ray (0., Float.infinity)) with + Some hit_result -> + let t = hit_result.t in + if (t > 0.0) + then let n = hit_result.normal in + mul 0.5 (Vec3.of_floats (n.x +. 1., n.y +. 1., n.z +. 1.)) + else 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}) + | 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})