From cc772aa6f9d3dd849a254c6743167cd7e6a3cdf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bor=20Gro=C5=A1elj=20Simi=C4=87?= Date: Tue, 11 Jan 2022 00:16:07 +0100 Subject: [PATCH] dielectric materials --- main.ha | 4 ++-- material.ha | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/main.ha b/main.ha index 640d564..0c49125 100644 --- a/main.ha +++ b/main.ha @@ -5,8 +5,8 @@ use time; fn init_scene() *hittable = { let ground = alloc(make_lambertian(&C(0.8, 0.8, 0.0))); - let center = alloc(make_lambertian(&C(0.7, 0.3, 0.3))); - let left = alloc(make_metal(&C(0.8, 0.8, 0.8), 0.3)); + let center = alloc(make_dielectric(1.5)); + let left = alloc(make_dielectric(1.2)); let right = alloc(make_metal(&C(0.8, 0.6, 0.2), 1.0)); let a = alloc(multi([])); append(a.arr, [ diff --git a/material.ha b/material.ha index e9cf3c0..78b544d 100644 --- a/material.ha +++ b/material.ha @@ -1,4 +1,4 @@ -use math::{absf64}; +use math::{absf64, powf64, sqrtf64}; export type scatterfunc = *fn( mat: *const material, @@ -73,3 +73,54 @@ fn metal_scatter( *att = m.albedo; return dot(r_out.direction, rec.normal) > 0.0; }; + +fn refract(v: *const vector, n: *const vector, r: f64) vector = { + let k = dot(neg(*v), *n); + let k = if (k < 1.0) k else 1.0; + let c1 = scale(sum(*v, scale(*n, k)), r); + let c2 = scale(*n, -sqrtf64(absf64(1.0 - dot(c1, c1)))); + return sum(c1, c2); +}; + +fn schlick_reflectance(cos: f64, r_ind: f64) f64 = { + let r0 = (1.0 - r_ind) / (1.0 + r_ind); + r0 = r0 * r0; + return r0 + (1.0 - r0) * powf64(1.0 - cos, 5.0); +}; + +type dielectric = struct { + material, + r_ind: f64, +}; + +fn make_dielectric(r: f64) dielectric = dielectric { + scatter = &dielectric_scatter, + r_ind = r, +}; + +fn dielectric_scatter( + m: *const material, + r_in: *const ray, + rec: *const hit_record, + att: *color, + r_out: *ray +) bool = { + let d = m: *const dielectric; + *att = C(1.0, 1.0, 1.0); + + let r_ind = if (rec.front_face) 1.0 / d.r_ind else d.r_ind; + let unit_dir = unit(r_in.direction); + let cos = dot(neg(unit_dir), rec.normal); + let cos = if (cos < 1.0) cos else 1.0; + let sin = sqrtf64(1.0 - cos * cos); + *r_out = ray { + origin = rec.point, + direction = + if (r_ind * sin <= 1.0 + || schlick_reflectance(cos, r_ind) > random(0.0, 1.0)) + refract(&unit_dir, &rec.normal, r_ind) + else + reflect(&unit_dir, &rec.normal), + }; + return true; +}; -- 2.45.2