diff --git a/src/raytracer.ml b/src/raytracer.ml index dd3f0b69..f8736343 100644 --- a/src/raytracer.ml +++ b/src/raytracer.ml @@ -5,7 +5,7 @@ open Ray type material = Lambertian of Vec3.vec3 (* albedo *) | Metal of Vec3.vec3 * float (* albedo, fuzz *) - | DummyNone (* TODO: use option type instead *) + | Dielectric of float (* refractive index *) type sphere = { center: Vec3.vec3; radius: float; @@ -19,7 +19,7 @@ type hitable = Sphere of sphere type hit_rec = { t : float; p: Vec3.vec3; normal: Vec3.vec3; - mat: material; } + mat: material option; } type scatter = { ray : Ray.ray; color: Vec3.vec3; @@ -41,24 +41,51 @@ let rec random_in_unit_sphere () = let reflect v n = Vec3.sub v (Vec3.mul (2. *. (Vec3.dot v n)) n) -let hit_scatter rin hit_rec = +let refract v n ni_over_nt = + let uv = Vec3.unit_vector v in + let dt = Vec3.dot uv n in + let discriminant = 1.0 -. ((ni_over_nt*.ni_over_nt) *. (1.0 -. dt*.dt)) in + if discriminant > 0.0 + then + let refracted = (Vec3.sub (Vec3.mul ni_over_nt (Vec3.sub v (Vec3.mul dt n))) (Vec3.mul (sqrt discriminant) n)) in + Some(refracted) + else None + +let hit_scatter r_in hit_rec = match hit_rec.mat with (* reflect in random direction *) - Lambertian(albedo) -> + Some(Lambertian(albedo)) -> let target = (Vec3.add (Vec3.add hit_rec.p hit_rec.normal) (random_in_unit_sphere ())) in let scatter = { ray = Ray.create hit_rec.p (Vec3.sub target hit_rec.p); color = albedo; scatter = true;} in scatter (* "shiny"- angle of reflectance = angle of incidence *) - | Metal(albedo, fuzz) -> - let reflected = reflect (Vec3.unit_vector rin.dir) hit_rec.normal in + | Some(Metal(albedo, fuzz)) -> + let reflected = reflect (Vec3.unit_vector r_in.dir) hit_rec.normal in let scattered_ray = Ray.create hit_rec.p (Vec3.add reflected (Vec3.mul fuzz (random_in_unit_sphere ()))) in let scattered = { ray = scattered_ray; color = albedo; scatter = (Vec3.dot scattered_ray.dir hit_rec.normal) > 0.0;} in scattered - | DummyNone -> failwith "not a real material type" + + | Some(Dielectric(ref_idx)) -> + let reflected = reflect (Vec3.unit_vector r_in.dir) hit_rec.normal in + let attenuation = Vec3.of_floats (1.0, 1.0, 1.0) in + let (outward_normal, ni_over_nt) = + if (Vec3.dot r_in.dir hit_rec.normal) > 0.0 + then (Vec3.neg hit_rec.normal, ref_idx) + else (hit_rec.normal, 1.0 /. ref_idx) in + let scattered_ray = + match (refract r_in.dir outward_normal ni_over_nt) with + | Some(refracted) -> Ray.create hit_rec.p refracted + | None -> Ray.create hit_rec.p reflected in + let scattered = + { ray= scattered_ray; + color= attenuation; + scatter = false; } in + scattered + | None -> failwith "not a real material type" let hit_sphere sphere ray (tmin, tmax) = let oc = sub ray.origin sphere.center in @@ -77,7 +104,7 @@ let hit_sphere sphere ray (tmin, tmax) = Some { t = t; p = p; normal = mul (1. /. sphere.radius) (sub p sphere.center); - mat = sphere.mat + mat = Some(sphere.mat) } else let t = (-.b +. (sqrt discriminant)) /. a in @@ -87,7 +114,7 @@ let hit_sphere sphere ray (tmin, tmax) = Some { t = t; p = p; normal = mul (1. /. sphere.radius) (sub p sphere.center); - mat = sphere.mat; + mat = Some(sphere.mat); } else None else None @@ -100,7 +127,7 @@ let rec hit_world world ray (tmin, tmax) = None -> { t = tmax; p = Vec3.of_floats (-1., -1., -1.); normal = Vec3.of_floats (-1., -1., -1.); - mat = DummyNone} + mat = None } | Some(r) -> r in match (hit h ray (tmin, prev_rec.t)) with Some(r) -> Some r @@ -137,10 +164,13 @@ let write_to_file filename = let sphere3 = Sphere {center = Vec3.of_floats (-1.0, 0., -1.); radius = 0.5; mat = Metal ((Vec3.of_floats (0.8, 0.6, 0.2)), 0.4)} in - let sphere4 = Sphere {center = Vec3.of_floats (1.0, 0., -1.); + (* let sphere4 = Sphere {center = Vec3.of_floats (1.0, 0., -1.); *) + (* radius = 0.5; *) + (* mat = Metal ((Vec3.of_floats (0.8, 0.8, 0.8)), 0.1)} in *) + let sphere4 = Sphere {center = Vec3.of_floats (1.0, 0.0, -1.); radius = 0.5; - mat = Metal ((Vec3.of_floats (0.8, 0.8, 0.8)), 0.1)} in - let world = World [sphere3; sphere2; sphere1; sphere4] in + mat = Dielectric (1.5)} in + let world = World [sphere3; sphere2; sphere1; sphere4;] in let nx = 400 in let ny = 200 in diff --git a/src/vec3.ml b/src/vec3.ml index 8d24dfeb..98f79d74 100644 --- a/src/vec3.ml +++ b/src/vec3.ml @@ -15,6 +15,9 @@ let sub v w = y = v.y -. w.y; z = v.z -. w.z} +let neg v = + sub {x= 0.0; y=0.0; z=0.0} v + let dot v w = v.x*.w.x +. v.y*.w.y +.v.z*.w.z diff --git a/src/vec3.mli b/src/vec3.mli index 10861db0..38421dd4 100644 --- a/src/vec3.mli +++ b/src/vec3.mli @@ -5,6 +5,7 @@ type vec3 = { x: float; val of_floats : float * float * float -> vec3 val add : vec3 -> vec3 -> vec3 val sub : vec3 -> vec3 -> vec3 +val neg : vec3 -> vec3 val dot : vec3 -> vec3 -> float val cross: vec3 -> vec3 -> vec3 val mul : float -> vec3 -> vec3