From 1380a1a07f211964979128274ecc314465bc3ce1 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Fri, 11 Mar 2016 11:32:36 +0545 Subject: [PATCH] Add types hitable to support World of multiple objects --- src/raytracer.ml | 71 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/src/raytracer.ml b/src/raytracer.ml index 8990ad01..ca4d2013 100644 --- a/src/raytracer.ml +++ b/src/raytracer.ml @@ -6,28 +6,83 @@ open Ray type sphere = { center: Vec3.vec3; radius: float } -let hit_sphere sphere ray = +type hitable = Sphere of sphere + | World of hitable list + +type hit = { t : float; + p: Vec3.vec3; + normal: Vec3.vec3; + hit: bool } + +let hit_sphere sphere ray (tmin, tmax) = let oc = sub ray.origin sphere.center in let a = dot ray.dir ray.dir in let b = (dot oc ray.dir) in 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 (-.b +. (sqrt discriminant)) /. a - else -1.0 + then + 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 + 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 + +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) +and hit h ray (tmin, tmax) = + match h with + Sphere s -> hit_sphere s ray (tmin, tmax) + | World w -> hit_world w ray (tmin, tmax) + let get_color ray = - let sphere = {center = Vec3.of_floats (0., 0., -1.); - radius = 0.5 } in - let t = (hit_sphere sphere ray) in - if (t > 0.0) - then let n = unit_vector (sub (Ray.point_at_parameter ray t) sphere.center) in + let sphere1 = Sphere {center = Vec3.of_floats (0., 0., -1.); + 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 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 nx = 200 in let ny = 100 in