@@ 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, [
@@ 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;
+};