aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Lasseter <user@4574.co.uk>2024-06-13 14:38:50 +0100
committerNat Lasseter <user@4574.co.uk>2024-06-13 14:38:50 +0100
commit69e0357135a49157ed7a8c2e57c331e960422e15 (patch)
tree2402ef255cf24afff14ac653826386e615faee8b
parentb976ce98be7275bf92e01f6c86bf2b694530481e (diff)
Chapter 11
-rw-r--r--lib/hittable.rb6
-rw-r--r--lib/material.rb31
-rw-r--r--lib/vec3.rb7
-rwxr-xr-xrtiaw12
4 files changed, 48 insertions, 8 deletions
diff --git a/lib/hittable.rb b/lib/hittable.rb
index facdd14..2a433d8 100644
--- a/lib/hittable.rb
+++ b/lib/hittable.rb
@@ -2,12 +2,12 @@ class HitRecord
def initialize(point, t, ray, out_normal, material)
@point = point
@t = t
- front_face = ray.direction.dot(out_normal) < 0
- @normal = front_face ? out_normal : -out_normal
+ @front_face = ray.direction.dot(out_normal) < 0
+ @normal = @front_face ? out_normal : -out_normal
@material = material
end
- attr_accessor :point, :normal, :t, :material
+ attr_reader :point, :normal, :t, :front_face, :material
end
class Hittable
diff --git a/lib/material.rb b/lib/material.rb
index c935147..752b85f 100644
--- a/lib/material.rb
+++ b/lib/material.rb
@@ -36,3 +36,34 @@ class Metal < Material
end
end
end
+
+class Dielectric < Material
+ def initialize(ref_index)
+ @ref_index = ref_index
+ end
+
+ def attenuation
+ Colour.new(1.0, 1.0, 1.0)
+ end
+
+ def scatter(ray, record)
+ ri = record.front_face ? (1.0 / @ref_index) : @ref_index
+ unit_dir = ray.direction.unit
+ costheta = [(-unit_dir).dot(record.normal), 1.0].min
+ sintheta = (1.0 - costheta ** 2) ** 0.5
+
+ cannot_refract = ri * sintheta > 1.0
+ maybe_reflect_anyway = Dielectric.reflectance(costheta, ri) > rand
+
+ refr = cannot_refract || maybe_reflect_anyway ?
+ unit_dir.reflect(record.normal) :
+ unit_dir.refract(record.normal, ri)
+
+ Ray.new(record.point, refr)
+ end
+
+ def self.reflectance(costheta, ri)
+ r0 = ((1.0 - ri) / (1.0 + ri)) ** 2
+ r0 + (1.0 - r0) * (1.0 - costheta) ** 5
+ end
+end
diff --git a/lib/vec3.rb b/lib/vec3.rb
index 3069b65..478fe4c 100644
--- a/lib/vec3.rb
+++ b/lib/vec3.rb
@@ -60,6 +60,13 @@ class Vec3
self - normal * dot(normal) * 2
end
+ def refract(normal, etaratio)
+ costheta = [(-self).dot(normal), 1.0].min
+ rout_perp = (self + normal * costheta) * etaratio
+ rout_parr = normal * -((1.0 - rout_perp.mag_sqr).abs ** 0.5)
+ rout_perp + rout_parr
+ end
+
def in_unit_sphere?
mag_sqr < 1
end
diff --git a/rtiaw b/rtiaw
index 71b4fbd..45487b9 100755
--- a/rtiaw
+++ b/rtiaw
@@ -10,14 +10,16 @@ require 'material'
mat_ground = Lambertian.new(0.8, 0.8, 0.0)
mat_centre = Lambertian.new(0.1, 0.2, 0.5)
-mat_left = Metal.new(0.8, 0.8, 0.8, 0.3)
+mat_left = Dielectric.new(1.5)
+mat_bubble = Dielectric.new(1 / 1.5)
mat_right = Metal.new(0.8, 0.6, 0.2, 1.0)
world = Hittables.new
-world << Sphere.new(0, -100.5, -1, 100, mat_ground)
-world << Sphere.new(0, 0, -1, 0.5, mat_centre)
-world << Sphere.new(-1, 0, -1, 0.5, mat_left)
-world << Sphere.new(1, 0, -1, 0.5, mat_right)
+world << Sphere.new( 0, -100.5, -1, 100, mat_ground)
+world << Sphere.new( 0, 0, -1.2, 0.5, mat_centre)
+world << Sphere.new(-1, 0, -1, 0.5, mat_left)
+world << Sphere.new(-1, 0, -1, 0.4, mat_bubble)
+world << Sphere.new( 1, 0, -1, 0.5, mat_right)
camera = Camera.new(400, 16.0 / 9)
camera.render(world)