aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Lasseter <user@4574.co.uk>2024-06-24 22:51:51 +0100
committerNat Lasseter <user@4574.co.uk>2024-06-24 22:51:51 +0100
commit3deef4d969dd50ddf540b80fe43ef16af5c17169 (patch)
tree456754a9bffb31471f2e64698afb8ee95aebca93
parentd248e30d365d5e401d5cd372aa415fb2f9a39326 (diff)
Chapter 11
-rw-r--r--hittable.go6
-rw-r--r--material.go46
-rw-r--r--rtiaw.go4
-rw-r--r--vec3.go9
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);
+}