mirror of
https://github.com/c-cube/moonpool.git
synced 2025-12-12 22:10:46 -05:00
155 lines
4.6 KiB
OCaml
155 lines
4.6 KiB
OCaml
open Core.Std
|
|
open Printf
|
|
open Vec3
|
|
open Ray
|
|
|
|
type sphere = { center: Vec3.vec3;
|
|
radius: float }
|
|
|
|
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
|
|
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 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
|
|
let oc = Out_channel.create filename in
|
|
fprintf oc "P3\n";
|
|
fprintf oc "%d\n" nx;
|
|
fprintf oc "%d\n" ny;
|
|
fprintf oc "\n255\n";
|
|
let lower_left_corner = Vec3.of_floats (-2., -1., -1.) in
|
|
let horizontal = Vec3.of_floats (4., 0., 0.) in
|
|
let vertical = Vec3.of_floats (0., 2., 0.) in
|
|
let origin = Vec3.of_floats (0., 0., 0.) in
|
|
let color = ref {x=0.; y=0.; z=0.} in
|
|
for j = ny downto 1 do
|
|
for i = 0 to nx-1 do
|
|
let u = (Float.of_int i) /. (Float.of_int nx) in
|
|
let v = (Float.of_int j) /. (Float.of_int ny) in
|
|
|
|
let r = { origin = origin;
|
|
dir = Vec3.add lower_left_corner (Vec3.add (Vec3.mul u horizontal) (Vec3.mul v vertical)) } in
|
|
color := get_color r;
|
|
|
|
let {x=r; y=g; z=b} = !color in
|
|
let (ir, ig, ib) = (Int.of_float (r*.255.99),
|
|
Int.of_float (g*.255.99),
|
|
Int.of_float (b*.255.99)) in
|
|
fprintf oc "%d " ir;
|
|
fprintf oc "%d " ig;
|
|
fprintf oc "%d \n" ib;
|
|
done
|
|
done;
|
|
Out_channel.close oc;
|
|
;;
|
|
|
|
|
|
let main() =
|
|
let nx = 200 in
|
|
let ny = 100 in
|
|
print_string "P3\n";
|
|
printf "%d\n" nx;
|
|
printf "%d\n" ny;
|
|
print_string "\n255\n";
|
|
|
|
let lower_left_corner = Vec3.of_floats (-2., -1., -1.) in
|
|
let horizontal = Vec3.of_floats (4., 0., 0.) in
|
|
let vertical = Vec3.of_floats (0., 2., 0.) in
|
|
let origin = Vec3.of_floats (0., 0., 0.) in
|
|
let color = ref {x=0.; y=0.; z=0.} in
|
|
for j = ny downto 1 do
|
|
for i = 0 to nx-1 do
|
|
let u = (Float.of_int i) /. (Float.of_int nx) in
|
|
let v = (Float.of_int j) /. (Float.of_int ny) in
|
|
|
|
let r = { origin = origin;
|
|
dir = Vec3.add lower_left_corner (Vec3.add (Vec3.mul u horizontal) (Vec3.mul v vertical)) } in
|
|
color := get_color r;
|
|
|
|
let {x=r; y=g; z=b} = !color in
|
|
let (ir, ig, ib) = (Int.of_float (r*.255.99),
|
|
Int.of_float (g*.255.99),
|
|
Int.of_float (b*.255.99)) in
|
|
printf "%d " ir;
|
|
printf "%d " ig;
|
|
printf "%d " ib;
|
|
print_newline();
|
|
done
|
|
done
|
|
;;
|
|
|
|
(* main() *)
|