aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--lib/camera.rb63
-rw-r--r--lib/interval.rb14
-rw-r--r--lib/ray.rb10
-rw-r--r--lib/vec3.rb7
-rwxr-xr-xrtiaw70
6 files changed, 95 insertions, 71 deletions
diff --git a/Makefile b/Makefile
index 3536afe..fd3f4e6 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ out.ppm: rtiaw $(wildcard lib/*.rb)
.phony: view clean
view: out.ppm
- eog out.ppm &
+ xv out.ppm
clean:
rm -f out.ppm
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
diff --git a/rtiaw b/rtiaw
index 5fb7e5a..82e4303 100755
--- a/rtiaw
+++ b/rtiaw
@@ -1,79 +1,15 @@
#!/usr/bin/env ruby
-start = Time.now.to_f
-
$LOAD_PATH.unshift File.dirname(__FILE__) + '/lib'
require 'interval'
require 'vec3'
require 'ray'
require 'hittable'
+require 'camera'
-def ray_colour(ray, world)
- if rec = world.hit(ray, Interval.new(0, Float::INFINITY))
- return (Colour.new(1,1,1) + rec.normal) * 0.5
- end
-
- unit_dir = ray.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
-
-# Define image
-width = 400
-aspect = 16.0 / 9
-max = 255
-
-# Calculate height
-height = (width / aspect).to_i
-height = height < 1 ? 1 : height
-
-# World
world = Hittables.new
world << Sphere.new(0,0,-1, 0.5)
world << Sphere.new(0,-100.5,-1, 100)
-# 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 -
- Vec3.new(0, 0, c_focallength) -
- v_u / 2 -
- v_v / 2
-p_00loc = v_upperleft +
- (pd_u + pd_v) / 2
-
-puts <<-EOH
-P3
-#{width} #{height}
-#{max}
-EOH
-
-height.times do |row|
- $stderr.print "Scanlines remaining: %4d" % (height - row)
- width.times do |col|
- p_centre = p_00loc + (pd_u * col) + (pd_v * row)
- ray_dir = p_centre - c_centre
- ray = Ray.new(c_centre, ray_dir)
-
- p_colour = ray_colour(ray, world)
- puts p_colour.to_ppm
- end
- puts
-end
-
-finish = Time.now.to_f
-took = finish - start
-
-$stderr.puts "Done. Took %4.2f seconds. " % took
+camera = Camera.new(400, 16.0 / 9)
+camera.render(world)