aboutsummaryrefslogtreecommitdiff
path: root/material.go
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 /material.go
parentd248e30d365d5e401d5cd372aa415fb2f9a39326 (diff)
Chapter 11
Diffstat (limited to 'material.go')
-rw-r--r--material.go46
1 files changed, 44 insertions, 2 deletions
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();
+}