From 51416f5dfac39b6ede8340b57b9bed4eb3edc646 Mon Sep 17 00:00:00 2001 From: Nat Lasseter Date: Wed, 12 Jun 2024 21:26:19 +0100 Subject: Done Chapter 8 --- lib/camera.rb | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/interval.rb | 14 +++++++++++-- lib/ray.rb | 10 +++++++++ lib/vec3.rb | 7 ++++++- 4 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 lib/camera.rb (limited to 'lib') diff --git a/lib/camera.rb b/lib/camera.rb new file mode 100644 index 0000000..f8721bb --- /dev/null +++ b/lib/camera.rb @@ -0,0 +1,63 @@ +class Camera + def initialize(width = 100, aspect = 1.0, aliasing = 10) + @width = width + @aspect = aspect + @aliasing = aliasing + + # Height + @height = (@width / @aspect).to_i + @height = @height < 1 ? 1 : @height + + # Camera + c_focallength = 1.0 + @c_centre = Point.new(0,0,0) + + # Viewport + @v_height = 2.0 + @v_width = @v_height * @width.to_f / @height + v_u = Vec3.new(@v_width, 0, 0) + v_v = Vec3.new(0, -@v_height, 0) + + # Pixel deltas + @pd_u = v_u / @width + @pd_v = v_v / @height + + # Upper left pixel + v_upperleft = @c_centre - v_u / 2 - v_v / 2 - + Vec3.new(0, 0, c_focallength) + @p00_loc = v_upperleft + (@pd_u + @pd_v) / 2 + end + + def render(world) + start = Time.now.to_f + + puts "P3" + puts "#{@width} #{@height}" + puts "255" + + @height.times do |row| + $stderr.print "Scanlines remaining: %4d" % (@height - row) + @width.times do |col| + p_colour = Colour.new + @aliasing.times do + p_colour += get_ray(row, col).colour(world) + end + puts (p_colour / @aliasing).to_ppm + end + puts + end + + finish = Time.now.to_f + took = finish - start + + $stderr.puts "Done. Took %4.2f seconds. " % took + end + + def get_ray(row, col) + p_sample = @p00_loc + + @pd_u * (col + rand - 0.5) + + @pd_v * (row + rand - 0.5) + + Ray.new(@c_centre, p_sample - @c_centre) + end +end diff --git a/lib/interval.rb b/lib/interval.rb index 0aa787f..3ba7e09 100644 --- a/lib/interval.rb +++ b/lib/interval.rb @@ -1,7 +1,7 @@ class Interval def initialize(min = Float::INFINITY, max = -Float::INFINITY) - @min = min - @max = max + @min = min.to_f + @max = max.to_f end attr_reader :min, :max @@ -17,4 +17,14 @@ class Interval def surround?(x) min < x && x < max end + + def sample + rand(@min...@max) + end + + def clamp(x) + return @min if x < @min + return @max if x > @max + x + end end diff --git a/lib/ray.rb b/lib/ray.rb index 4d282cb..47f2b26 100644 --- a/lib/ray.rb +++ b/lib/ray.rb @@ -9,4 +9,14 @@ class Ray def at(time) @origin + (@direction * time) end + + def colour(world) + if rec = world.hit(self, Interval.new(0, Float::INFINITY)) + return (Colour.new(1,1,1) + rec.normal) * 0.5 + end + + unit_dir = direction.unit + a = (unit_dir.y + 1) / 2 + Colour.new(1.0, 1.0, 1.0) * (1-a) + Colour.new(0.5, 0.7, 1.0) * a + end end diff --git a/lib/vec3.rb b/lib/vec3.rb index 6287813..b9a5a73 100644 --- a/lib/vec3.rb +++ b/lib/vec3.rb @@ -69,6 +69,11 @@ class Colour < Vec3 def b; @z; end def to_ppm - "%3d %3d %3d" % [(r * 255.999).to_i, (g * 255.999).to_i, (b * 255.999).to_i] + intensity = Interval.new(0.0, 0.999) + "%3d %3d %3d" % [ + (intensity.clamp(r) * 256).to_i, + (intensity.clamp(g) * 256).to_i, + (intensity.clamp(b) * 256).to_i + ] end end -- cgit v1.2.1