#!/usr/bin/env ruby start = Time.now.to_f $LOAD_PATH.unshift File.dirname(__FILE__) + '/lib' require 'interval' require 'vec3' require 'ray' require 'hittable' 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