From 3deef4d969dd50ddf540b80fe43ef16af5c17169 Mon Sep 17 00:00:00 2001 From: Nat Lasseter Date: Mon, 24 Jun 2024 22:51:51 +0100 Subject: Chapter 11 --- hittable.go | 6 ++++-- material.go | 46 ++++++++++++++++++++++++++++++++++++++++++++-- rtiaw.go | 4 +++- vec3.go | 9 +++++++++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/hittable.go b/hittable.go index 42599ab..ac5e996 100644 --- a/hittable.go +++ b/hittable.go @@ -11,12 +11,14 @@ type HitRecord struct { P Vec3 N Vec3 T float64 + F bool Mat Material } func (rec *HitRecord) SetFaceNormal(r Ray, out_n Vec3) { - if r.Direction.Dot(out_n) < 0 { - rec.N = out_n + rec.F = r.Direction.Dot(out_n) < 0; + if rec.F { + rec.N = out_n; } else { rec.N = out_n.Neg(); } diff --git a/material.go b/material.go index 66ea256..62a0467 100644 --- a/material.go +++ b/material.go @@ -1,5 +1,9 @@ package main +import ( + maths "math" +) + //Material type Material interface { @@ -7,7 +11,7 @@ type Material interface { Scatter(r Ray, hit HitRecord) Ray } -//Lambertian +//Lambertian < Material type Lambertian struct { Albedo Vec3 @@ -25,7 +29,7 @@ func (l Lambertian) Scatter(r Ray, hit HitRecord) Ray { return Ray{hit.P, scat_dir, true}; } -//Metal +//Metal < Material type Metal struct { Albedo Vec3 @@ -42,3 +46,41 @@ func (m Metal) Scatter(r Ray, hit HitRecord) Ray { valid := refl.Dot(hit.N) > 0; return Ray{hit.P, refl, valid}; } + +//Dielectric < Material + +type Dielectric struct { + RefractionIndex float64 +} + +func (d Dielectric) Attenuation() Vec3 { + return SplatVec3(1); +} + +func (d Dielectric) Scatter(r Ray, hit HitRecord) Ray { + ri := d.RefractionIndex; + if hit.F { + ri = 1.0 / ri; + } + + unit_dir := r.Direction.Unit(); + cos_theta := maths.Min(unit_dir.Neg().Dot(hit.N), 1.0); + sin_theta := maths.Sqrt(1.0 - maths.Pow(cos_theta, 2)); + + cannot_refract := ri * sin_theta > 1.0; + + var dir Vec3; + if cannot_refract || schlick_reflect(cos_theta, ri) { + dir = unit_dir.Reflect(hit.N); + } else { + dir = unit_dir.Refract(hit.N, ri); + } + + return Ray{hit.P, dir, true}; +} + +func schlick_reflect(cos_theta float64, ri float64) bool { + r0 := maths.Pow((1 - ri) / (1 + ri), 2); + approx := r0 + (1 - r0) * maths.Pow(1 - cos_theta, 5); + return approx > Interval{0, 1}.Sample(); +} diff --git a/rtiaw.go b/rtiaw.go index d95501d..1427fbf 100644 --- a/rtiaw.go +++ b/rtiaw.go @@ -11,13 +11,15 @@ func main() { mat_ground := Lambertian{Vec3{0.8, 0.8, 0}}; mat_centre := Lambertian{Vec3{0.1, 0.2, 0.5}}; - mat_left := Metal{Vec3{0.8, 0.8, 0.8}, 0.3}; + mat_left := Dielectric{1.5}; + mat_bubble := Dielectric{1.0 / 1.5}; mat_right := Metal{Vec3{0.8, 0.6, 0.2}, 1.0}; var world Hittables; world.Add(Sphere{Vec3{ 0, -100.5, -1 }, 100 , mat_ground}); world.Add(Sphere{Vec3{ 0, 0 , -1.2}, 0.5, mat_centre}); world.Add(Sphere{Vec3{-1.0, 0 , -1 }, 0.5, mat_left}); + world.Add(Sphere{Vec3{-1.0, 0 , -1 }, 0.4, mat_bubble}); world.Add(Sphere{Vec3{ 1.0, 0 , -1 }, 0.5, mat_right}); cam := NewCamera(400, 16.0/9.0, 100, 50); diff --git a/vec3.go b/vec3.go index a540b7c..f590625 100644 --- a/vec3.go +++ b/vec3.go @@ -95,3 +95,12 @@ func RandomVec3OnUnitSphere() (v Vec3) { func (v Vec3) Reflect(n Vec3) Vec3 { return v.Sub(SplatVec3(2 * v.Dot(n)).Mul(n)); } + +func (v Vec3) Refract(n Vec3, eta_ratio float64) Vec3 { + cos_theta := maths.Min(v.Neg().Dot(n), 1.0); + r_out_perp := SplatVec3(eta_ratio). + Mul(v.Add(SplatVec3(cos_theta).Mul(n))); + rops := -maths.Sqrt(maths.Abs(1.0 - r_out_perp.MagSqr())); + r_out_parr := SplatVec3(rops).Mul(n); + return r_out_perp.Add(r_out_parr); +} -- cgit v1.2.1