1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
class Camera
def initialize(width = 100, aspect = 1.0,
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))
@width = width
@aliasing = aliasing
@depth = depth
# Height
@height = (@width / aspect).to_i
@height = @height < 1 ? 1 : @height
# 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
# Camera basis vectors
w = (lookfrom - lookat).unit
u = vup.cross(w).unit
v = w.cross(u)
v_u = u * v_width
v_v = -v * v_height
# 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 -
w * 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 "[GScanlines remaining: %4d" % (@height - row)
@width.times do |col|
p_colour = Colour.new
@aliasing.times do
p_colour += get_ray(row, col).colour(world, @depth)
end
puts (p_colour / @aliasing).to_ppm
end
puts
end
finish = Time.now.to_f
took = finish - start
$stderr.puts "[GDone. 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
|