aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNat Lasseter <user@4574.co.uk>2024-06-14 12:23:49 +0100
committerNat Lasseter <user@4574.co.uk>2024-06-14 12:23:49 +0100
commit3549acb5dbd2f6fe43be6cce9828785ccead7e77 (patch)
treec4cb0f2db631d3b60b641f6c8e654663940b3d38 /lib
parent3bf56da7aa64ea3ca05559a4e52df8f596bcf86b (diff)
Finished! Good god performance nope.HEADmain
Diffstat (limited to 'lib')
-rw-r--r--lib/camera.rb25
-rw-r--r--lib/hittable.rb4
-rw-r--r--lib/material.rb17
-rw-r--r--lib/vec3.rb27
4 files changed, 43 insertions, 30 deletions
diff --git a/lib/camera.rb b/lib/camera.rb
index 365ebcd..3ddf769 100644
--- a/lib/camera.rb
+++ b/lib/camera.rb
@@ -3,7 +3,8 @@ class Camera
aliasing: 10, depth: 10, vfov: 90.0,
lookfrom: Point.new(0, 0, 0),
lookat: Point.new(0, 0, -1),
- vup: Vec3.new(0, 1, 0))
+ vup: Vec3.new(0, 1, 0),
+ defocus_angle: 0, focus_dist: 10)
@width = width
@aliasing = aliasing
@depth = depth
@@ -14,13 +15,12 @@ class Camera
# Camera
@c_centre = lookfrom
- c_focallength = (lookfrom - lookat).mag
# Viewport
theta = vfov * Maths::PI / 180
h = Maths.tan(theta / 2)
- v_height = 2.0 * h * c_focallength
- v_width = v_height * @width.to_f / @height
+ v_height = 2.0 * h * focus_dist
+ v_width = (v_height * @width) / @height
# Camera basis vectors
w = (lookfrom - lookat).unit
@@ -36,8 +36,14 @@ class Camera
# Upper left pixel
v_upperleft = @c_centre - v_u / 2 - v_v / 2 -
- w * c_focallength
+ w * focus_dist
@p00_loc = v_upperleft + (@pd_u + @pd_v) / 2
+
+ @defocus_angle = defocus_angle
+ defocus_radius = focus_dist * Maths.tan((@defocus_angle / 2) *
+ Maths::PI / 180)
+ @defocus_disk_u = u * defocus_radius
+ @defocus_disk_v = v * defocus_radius
end
def render(world)
@@ -70,6 +76,13 @@ class Camera
@pd_u * (col + rand - 0.5) +
@pd_v * (row + rand - 0.5)
- Ray.new(@c_centre, p_sample - @c_centre)
+ ray_origin = @defocus_angle <= 0 ? @c_centre : defocus_disk_sample
+ ray_dir = p_sample - ray_origin
+ Ray.new(ray_origin, ray_dir)
+ end
+
+ def defocus_disk_sample
+ p = Vec3.random_in_unit(dimensions: 2)
+ @c_centre + @defocus_disk_u * p.x + @defocus_disk_v * p.y
end
end
diff --git a/lib/hittable.rb b/lib/hittable.rb
index 2a433d8..1e22613 100644
--- a/lib/hittable.rb
+++ b/lib/hittable.rb
@@ -45,8 +45,8 @@ class Hittables < Hittable
end
class Sphere < Hittable
- def initialize(ox, oy, oz, radius = 1, material)
- @centre = Point.new(ox, oy, oz)
+ def initialize(centre, radius = 1, material)
+ @centre = centre
@radius = radius
@material = material
end
diff --git a/lib/material.rb b/lib/material.rb
index 752b85f..14eb5f9 100644
--- a/lib/material.rb
+++ b/lib/material.rb
@@ -1,6 +1,6 @@
class Material
- def initialize(r, g, b)
- @albedo = Colour.new(r, g, b)
+ def initialize(albedo)
+ @albedo = albedo
end
def attenuation
@@ -14,21 +14,21 @@ end
class Lambertian < Material
def scatter(ray, record)
- scat = record.normal + Vec3.random_unit
+ scat = record.normal + Vec3.random_in_unit
scat = rec.normal if scat.near_zero?
Ray.new(record.point, scat)
end
end
class Metal < Material
- def initialize(r, g, b, fuzz)
+ def initialize(albedo, fuzz)
@fuzz = fuzz < 1 ? fuzz : 1
- super(r, g, b)
+ super(albedo)
end
def scatter(ray, record)
refl = ray.direction.reflect(record.normal)
- refl = refl.unit + (Vec3.random_unit * @fuzz)
+ refl = refl.unit + (Vec3.random_in_unit * @fuzz)
if refl.dot(record.normal) > 0
Ray.new(record.point, refl)
else
@@ -40,10 +40,7 @@ end
class Dielectric < Material
def initialize(ref_index)
@ref_index = ref_index
- end
-
- def attenuation
- Colour.new(1.0, 1.0, 1.0)
+ super(Colour.new(1.0, 1.0, 1.0))
end
def scatter(ray, record)
diff --git a/lib/vec3.rb b/lib/vec3.rb
index 478fe4c..46d8ee1 100644
--- a/lib/vec3.rb
+++ b/lib/vec3.rb
@@ -1,8 +1,8 @@
class Vec3
- def initialize(x = 0, y = 0, z = 0)
- @x = x.to_f
- @y = y.to_f
- @z = z.to_f
+ def initialize(x = 0.0, y = 0.0, z = 0.0)
+ @x = x
+ @y = y
+ @z = z
end
attr_reader :x, :y, :z
@@ -67,7 +67,7 @@ class Vec3
rout_perp + rout_parr
end
- def in_unit_sphere?
+ def in_unit?
mag_sqr < 1
end
@@ -79,18 +79,21 @@ class Vec3
"{#{@x}, #{@y}, #{@z}}"
end
- def self.random(min = 0, max = 1)
- interval = Interval.new(min.to_f, max.to_f)
- Vec3.new(interval.sample, interval.sample, interval.sample)
+ def self.random(min: -1.0, max: 1.0, dimensions: 3)
+ interval = Interval.new(min, max)
+ self.new(
+ dimensions >= 1 ? interval.sample : 0,
+ dimensions >= 2 ? interval.sample : 0,
+ dimensions >= 3 ? interval.sample : 0
+ )
end
- def self.random_unit(normal = nil)
+ def self.random_in_unit(normal: nil, dimensions: 3)
p = nil
while p.nil?
- c = Vec3.random
- p = c.unit if c.in_unit_sphere?
+ c = self.random(dimensions: dimensions)
+ p = c.unit if c.in_unit?
end
-
normal.nil? || p.dot(normal) > 0 ? p : -p
end
end