rray 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f03f9a2499958c6af45796be767ad0f40142f8a149bcef505d4e0fcb920956b8
4
- data.tar.gz: fe1bc6387e3dd6b3515fe143177c48ad73b1e49135a96d192c0ac22d71e1714f
3
+ metadata.gz: c1f6b0d451c5f0098de3d1aaf967766038c58b622dab31a26b3d4400a28c72bd
4
+ data.tar.gz: 97a44a8efa2be4a28e81b6dcf10de54646bb034787326787e3d6925fe79afab8
5
5
  SHA512:
6
- metadata.gz: 6317e23620a5113b9ed5e34e0e5ffd8a92dd1dd2ceca3852145bee24f6f611a6c8a07516bb53a4d1bb57e3c4623ba6f53b2e488510b6d38fc14ff45a5537e00d
7
- data.tar.gz: ba1af605e9ccd88cae8602c8f4353b51aa3a5584a0504e82e10153466941b289989153310aa300464f53982228c598ca1c340182cc482662deb513b40783b54f
6
+ metadata.gz: 50d401573d8e62609cd940451580269fe0f153d086217153f9a3ca9ec571e1ddb0c28a456adb0ae9c55661b67c5733dab4e4b81817290b950618ca475c4d9ed9
7
+ data.tar.gz: 0d46651fc158a7cef699a2b4371a0a5892df107c1f0f5c8a93778b7f03fd76a63706a175d4775a6ebc28b55ad428ae601463802a1519b33e42ef9392f190d508
data/lib/rray/aabb.rb ADDED
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './interval'
4
+
5
+ module Rray
6
+ class AABB
7
+ attr_accessor :x, :y, :z
8
+
9
+ # The default AABB is empty, since intervals are empty by default.
10
+ def initialize(x = Interval.new, y = Interval.new, z = Interval.new)
11
+ @x = x
12
+ @y = y
13
+ @z = z
14
+ end
15
+
16
+ # Treat the two points a and b as extrema for the bounding box, so we don't require a
17
+ # particular minimum/maximum coordinate order.
18
+ def self.from_points(a, b)
19
+ new(
20
+ a.x < b.x ? Interval.new(a.x, b.x) : Interval.new(b.x, a.x),
21
+ a.y < b.y ? Interval.new(a.y, b.y) : Interval.new(b.y, a.y),
22
+ a.z < b.z ? Interval.new(a.z, b.z) : Interval.new(b.z, a.z)
23
+ )
24
+ end
25
+
26
+ def self.from_aabbs(box0, box1)
27
+ new(
28
+ Interval.from_intervals(box0.x, box1.x),
29
+ Interval.from_intervals(box0.y, box1.y),
30
+ Interval.from_intervals(box0.z, box1.z)
31
+ )
32
+ end
33
+
34
+ def [](n)
35
+ case n
36
+ when 0 then x
37
+ when 1 then y
38
+ when 2 then z
39
+ end
40
+ end
41
+
42
+ def hit(r, ray_t)
43
+ t = Interval.from_range(ray_t)
44
+
45
+ (0...3).each do |axis|
46
+ ax = self[axis]
47
+ adinv = 1.0 / r.direction[axis]
48
+
49
+ t0 = (ax.min - r.origin[axis]) * adinv
50
+ t1 = (ax.max - r.origin[axis]) * adinv
51
+
52
+ if t0 < t1
53
+ t.min = t0 if t0 > t.min
54
+ t.max = t1 if t1 < t.max
55
+ else
56
+ t.min = t1 if t1 > t.min
57
+ t.max = t0 if t0 < t.max
58
+ end
59
+
60
+ return false if t.max <= t.min
61
+ end
62
+
63
+ true
64
+ end
65
+
66
+ # Returns the index of the longest axis of the bounding box.
67
+ def longest_axis
68
+ if x.size > y.size
69
+ x.size > z.size ? 0 : 2
70
+ else
71
+ y.size > z.size ? 1 : 2
72
+ end
73
+ end
74
+
75
+ EMPTY = new(Interval::EMPTY, Interval::EMPTY, Interval::EMPTY)
76
+ UNIVERSE = new(Interval::UNIVERSE, Interval::UNIVERSE, Interval::UNIVERSE)
77
+ end
78
+ end
data/lib/rray/camera.rb CHANGED
@@ -66,15 +66,27 @@ module Rray
66
66
  # Construct a camera ray originating from the defocus disk and directed at a randomly
67
67
  # sampled point around the pixel location x, y.
68
68
  def ray(x, y)
69
- offset = Util.sample_square
69
+ offset = Vec3.sample_square
70
70
  pixel_sample = pixel00_loc +
71
71
  (pixel_delta_u * (x + offset.x)) +
72
72
  (pixel_delta_v * (y + offset.y))
73
73
 
74
74
  ray_origin = defocus_angle <= 0 ? center : defocus_disk_sample
75
75
  ray_direction = pixel_sample - ray_origin
76
+ ray_time = rand
76
77
 
77
- Ray.new(ray_origin, ray_direction)
78
+ Ray.new(ray_origin, ray_direction, ray_time)
79
+ end
80
+
81
+ def export
82
+ {
83
+ vfov: vfov,
84
+ lookfrom: lookfrom.to_a,
85
+ lookat: lookat.to_a,
86
+ vup: vup.to_a,
87
+ defocus_angle: defocus_angle,
88
+ focus_dist: focus_dist
89
+ }
78
90
  end
79
91
 
80
92
  private
data/lib/rray/hit.rb CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  module Rray
4
4
  class Hit
5
- attr_accessor :point, :normal, :t, :mat, :front_face
5
+ attr_accessor :point, :normal, :t, :material, :front_face
6
6
 
7
- def initialize(point, r, outward_normal, t, mat)
7
+ def initialize(point, r, outward_normal, t, material)
8
8
  @point = point
9
9
  @t = t
10
- @mat = mat
10
+ @material = material
11
11
 
12
- # Sets the hit record normal vector.
12
+ # Sets the hit's normal vector.
13
13
  # NOTE: the parameter `outward_normal` is assumed to have unit length.
14
14
 
15
15
  @front_face = r.direction.dot(outward_normal) < 0
data/lib/rray/interval.rb CHANGED
@@ -4,11 +4,24 @@ module Rray
4
4
  class Interval
5
5
  attr_accessor :min, :max
6
6
 
7
- def initialize(min, max)
7
+ # Default interval is empty
8
+ def initialize(min = Float::INFINITY, max = -Float::INFINITY)
8
9
  @min = min
9
10
  @max = max
10
11
  end
11
12
 
13
+ def self.from_range(r)
14
+ new(r.min, r.max)
15
+ end
16
+
17
+ # Create the interval tightly enclosing the two input intervals.
18
+ def self.from_intervals(a, b)
19
+ new(
20
+ a.min <= b.min ? a.min : b.min,
21
+ a.max >= b.max ? a.max : b.max
22
+ )
23
+ end
24
+
12
25
  def size = max - min
13
26
  def include?(x) = min <= x && x <= max
14
27
  def surround?(x) = min < x && x < max
@@ -19,6 +32,15 @@ module Rray
19
32
  x
20
33
  end
21
34
 
35
+ def expand(delta)
36
+ padding = delta / 2.0
37
+ Interval.new(min - padding, max + padding)
38
+ end
39
+
40
+ def dup
41
+ Interval.new(min, max)
42
+ end
43
+
22
44
  EMPTY = new(Float::INFINITY, -Float::INFINITY)
23
45
  UNIVERSE = new(-Float::INFINITY, Float::INFINITY)
24
46
  end
@@ -3,9 +3,21 @@
3
3
  module Rray
4
4
  module Material
5
5
  class Base
6
+ def id
7
+ "#{type.downcase}-#{object_id.to_s(16)}"
8
+ end
9
+
10
+ def type
11
+ self.class.name.split('::').last
12
+ end
13
+
6
14
  def scatter(r_in, rec)
7
15
  raise NotImplementedError, "Implement #{self.class}#scatter"
8
16
  end
17
+
18
+ def export
19
+ raise NotImplementedError, "Implement #{self.class.name}#export"
20
+ end
9
21
  end
10
22
  end
11
23
  end
@@ -26,17 +26,24 @@ module Rray
26
26
  unit_direction.refract(rec.normal, ri)
27
27
  end
28
28
 
29
- scattered = Ray.new(rec.point, direction)
29
+ scattered = Ray.new(rec.point, direction, r_in.time)
30
30
 
31
31
  Scatter.new(scattered, attenuation)
32
32
  end
33
33
 
34
+ def export
35
+ {
36
+ type: "Dielectric",
37
+ refraction_index: refraction_index
38
+ }
39
+ end
40
+
34
41
  private
35
42
 
36
43
  def reflectance(cosine, ri)
37
44
  # Use Schlick's approximation for reflectance.
38
45
  r0 = ((1.0 - ri) / (1.0 + ri))**2
39
- r0 + (1-r0)*(1.0-cosine)**5
46
+ r0 + (1.0-r0)*(1.0-cosine)**5
40
47
  end
41
48
  end
42
49
  end
@@ -11,13 +11,20 @@ module Rray
11
11
 
12
12
  def scatter(r_in, rec)
13
13
  scatter_direction = rec.normal + Vec3.random_unit_vector
14
- scattered = Ray.new(rec.point, scatter_direction)
14
+ scattered = Ray.new(rec.point, scatter_direction, r_in.time)
15
15
 
16
16
  # Catch degenerate scatter direction
17
17
  scatter_direction = rec.normal if scatter_direction.zero?
18
18
 
19
19
  Scatter.new(scattered, albedo)
20
20
  end
21
+
22
+ def export
23
+ {
24
+ type: "Lambertian",
25
+ albedo: albedo.to_a
26
+ }
27
+ end
21
28
  end
22
29
  end
23
30
  end
@@ -13,11 +13,19 @@ module Rray
13
13
  def scatter(r_in, rec)
14
14
  reflected = r_in.direction.reflect(rec.normal)
15
15
  reflected = reflected.normalize.add(Vec3.random_unit_vector.mul(fuzz))
16
- scattered = Ray.new(rec.point, reflected)
16
+ scattered = Ray.new(rec.point, reflected, r_in.time)
17
17
  return nil if scattered.direction.dot(rec.normal) <= 0
18
18
 
19
19
  Scatter.new(scattered, albedo)
20
20
  end
21
+
22
+ def export
23
+ {
24
+ type: "Metal",
25
+ albedo: albedo.to_a,
26
+ fuzz: fuzz
27
+ }
28
+ end
21
29
  end
22
30
  end
23
31
  end
@@ -3,9 +3,25 @@
3
3
  module Rray
4
4
  module Object
5
5
  class Base
6
+ def id
7
+ "#{type.downcase}-#{object_id.to_s(16)}"
8
+ end
9
+
10
+ def type
11
+ self.class.name.split('::').last
12
+ end
13
+
6
14
  def hit(r, ray_t)
7
15
  raise NotImplementedError, "Implement #{self.class.name}#hit"
8
16
  end
17
+
18
+ def export
19
+ raise NotImplementedError, "Implement #{self.class.name}#export"
20
+ end
21
+
22
+ def bounding_box
23
+ raise NotImplementedError, "Implement #{self.class.name}#bounding_box"
24
+ end
9
25
  end
10
26
  end
11
27
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rray
4
+ module Object
5
+ class BVH < Base
6
+ attr_reader :bounding_box
7
+
8
+ def initialize(objects)
9
+ @bounding_box = AABB::EMPTY
10
+ objects.each do |object|
11
+ @bounding_box = AABB.from_aabbs(@bounding_box, object.bounding_box)
12
+ end
13
+
14
+ axis = @bounding_box.longest_axis
15
+
16
+ case objects.length
17
+ when 1
18
+ @left = @right = objects[0]
19
+ when 2
20
+ @left = objects[0]
21
+ @right = objects[1]
22
+ else
23
+ objects.sort_by! { _1.bounding_box[axis].min }
24
+ mid = objects.length / 2
25
+ @left = BVH.new(objects[0...mid])
26
+ @right = BVH.new(objects[mid..])
27
+ end
28
+ end
29
+
30
+ def hit(r, ray_t)
31
+ return nil unless bounding_box.hit(r, ray_t)
32
+
33
+ hit_left = @left.hit(r, ray_t)
34
+ hit_right = @right.hit(r, ray_t.min..(hit_left&.t || ray_t.max))
35
+
36
+ hit_right || hit_left
37
+ end
38
+
39
+ def export
40
+ raise NotImplementedError, "Cannot export BVH, perhaps you meant to use a group?"
41
+ end
42
+
43
+ def to_s(depth=0)
44
+ indent = " "*depth
45
+ "#{indent}BVH {\n" +
46
+ "#{indent} left=\n"+
47
+ "#{@left.to_s(depth+2)}\n"+
48
+ "#{indent} right=\n"+
49
+ "#{@right.to_s(depth+2)}\n"+
50
+ "#{indent}}"
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './bvh'
4
+
3
5
  module Rray
4
6
  module Object
5
7
  class Group < Base
@@ -7,25 +9,35 @@ module Rray
7
9
 
8
10
  def initialize(objects = [])
9
11
  @objects = objects
12
+ @bvh = BVH.new(objects)
10
13
  end
11
14
 
12
15
  def <<(object)
13
16
  objects << object
17
+ @bvh = BVH.new(objects)
18
+ object
14
19
  end
15
20
 
16
21
  def hit(r, ray_t)
17
- rec = nil
18
- closest_so_far = ray_t.end
22
+ @bvh.hit(r, ray_t)
23
+ end
19
24
 
20
- objects.each do |object|
21
- temp_rec = object.hit(r, ray_t.begin..closest_so_far)
22
- next unless temp_rec
25
+ def bounding_box
26
+ @bvh.bounding_box
27
+ end
23
28
 
24
- rec = temp_rec
25
- closest_so_far = rec.t
26
- end
29
+ def export
30
+ {
31
+ type: "Group",
32
+ objects: objects.map(&:export)
33
+ }
34
+ end
27
35
 
28
- rec
36
+ def to_s(depth=0)
37
+ indent = " "*depth
38
+ "#{indent}Group {\n" +
39
+ objects.map { "#{indent} #{_1.to_s(depth+1)}\n" } +
40
+ "#{indent}}"
29
41
  end
30
42
  end
31
43
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rray
4
+ module Object
5
+ class MovingSphere < Sphere
6
+ attr_accessor :center_vec
7
+
8
+ def initialize(center1, center2, radius, material)
9
+ super(center1, radius, material)
10
+ @center_vec = center2 - center1
11
+ rvec = Vec3.new(radius, radius, radius)
12
+ box1 = AABB.from_points(center1 - rvec, center1 + rvec)
13
+ box2 = AABB.from_points(center2 - rvec, center2 + rvec)
14
+ @bounding_box = AABB.from_aabbs(box1, box2)
15
+ end
16
+
17
+ # Linearly interpolate from center1 to center2 according to time, where t=0 yields
18
+ # center1, and t=1 yields center2.
19
+ def center_at(time = 0.0)
20
+ center + center_vec * time
21
+ end
22
+
23
+ def hit(r, ray_t)
24
+ super(r, ray_t, center_at(r.time))
25
+ end
26
+
27
+ def export
28
+ {
29
+ type: "MovingSphere",
30
+ center1: center.to_a,
31
+ center2: center_at(1.0).to_a,
32
+ radius: radius,
33
+ material: material.id
34
+ }
35
+ end
36
+
37
+ def to_s(depth=0)
38
+ indent = " "*depth
39
+ "#{indent}MovingSphere { radius=#{radius}, center=#{center}, vec=#{center_vec} }"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -3,15 +3,19 @@
3
3
  module Rray
4
4
  module Object
5
5
  class Sphere < Base
6
- attr_accessor :center, :radius, :mat
6
+ attr_accessor :center, :radius, :material
7
7
 
8
- def initialize(center, radius, mat)
8
+ attr_reader :bounding_box
9
+
10
+ def initialize(center, radius, material)
9
11
  @center = center
10
12
  @radius = radius
11
- @mat = mat
13
+ @material = material
14
+ rvec = Vec3.new(radius, radius, radius)
15
+ @bounding_box = AABB.from_points(center - rvec, center + rvec)
12
16
  end
13
17
 
14
- def hit(r, ray_t)
18
+ def hit(r, ray_t, center = @center)
15
19
  oc = center - r.origin
16
20
  a = r.direction.length_squared
17
21
  h = r.direction.dot(oc)
@@ -36,9 +40,23 @@ module Rray
36
40
  r,
37
41
  (point - center).div(radius),
38
42
  root,
39
- mat
43
+ material
40
44
  )
41
45
  end
46
+
47
+ def export
48
+ {
49
+ type: "Sphere",
50
+ center: center.to_a,
51
+ radius: radius,
52
+ material: material.id
53
+ }
54
+ end
55
+
56
+ def to_s(depth=0)
57
+ indent = " "*depth
58
+ "#{indent}Sphere { radius=#{radius}, center=#{center} }"
59
+ end
42
60
  end
43
61
  end
44
62
  end
data/lib/rray/ray.rb CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  module Rray
4
4
  class Ray
5
- attr_accessor :origin, :direction
5
+ attr_accessor :origin, :direction, :time
6
6
 
7
- def initialize(origin, direction)
7
+ def initialize(origin, direction, time = 0.0)
8
8
  @origin = origin
9
9
  @direction = direction
10
+ @time = time
10
11
  end
11
12
 
12
13
  def at(t) = (direction*t).add(origin)
13
14
 
14
- def dup = self.class.new(origin, direction)
15
+ def dup = self.class.new(origin, direction, time)
15
16
  end
16
17
  end
data/lib/rray/scene.rb CHANGED
@@ -17,6 +17,31 @@ module Rray
17
17
  Parser.new(json).parse
18
18
  end
19
19
 
20
+ def export
21
+ {
22
+ world: world.export,
23
+ camera: camera.export,
24
+ materials: export_materials
25
+ }
26
+ end
27
+
28
+ private
29
+
30
+ def export_materials
31
+ materials = {}
32
+ traverse do |object|
33
+ materials[object.material.id] ||= object.material.export
34
+ end
35
+ materials
36
+ end
37
+
38
+ def traverse(object = world, &block)
39
+ case object
40
+ when Object::Group then object.objects.each(&block)
41
+ else yield object
42
+ end
43
+ end
44
+
20
45
  class Parser
21
46
  class Error < Rray::Error; end
22
47
 
@@ -38,21 +63,34 @@ module Rray
38
63
  case mat["type"]
39
64
  when "Lambertian" then Material::Lambertian.new(Color.new(*mat["albedo"]))
40
65
  when "Metal" then Material::Metal.new(Color.new(*mat["albedo"]), mat["fuzz"])
41
- when "Dielectric" then Material::Dielectric.new(mat["refractive_index"])
42
- else raise ParserError, "unknown material type #{mat["type"]}"
66
+ when "Dielectric" then Material::Dielectric.new(mat["refraction_index"])
67
+ else raise Error, "unknown material type #{mat["type"]}"
43
68
  end
44
69
  end
45
70
 
46
71
  def parse_object(obj)
47
72
  case obj["type"]
48
- when "Group" then Object::Group.new(obj["objects"].map { parse_object(_1) })
49
- when "Sphere" then Object::Sphere.new(Point3.new(*obj["center"]), obj["radius"], material(obj["material"]))
50
- else raise ParserError, "unknown object type #{obj["type"]}"
73
+ when "Group" then parse_group(obj)
74
+ when "Sphere" then parse_sphere(obj)
75
+ when "MovingSphere" then parse_moving_sphere(obj)
76
+ else raise Error, "unknown object type #{obj["type"]}"
51
77
  end
52
78
  end
53
79
 
80
+ def parse_group(obj)
81
+ Object::Group.new(obj["objects"].map { parse_object(_1) })
82
+ end
83
+
84
+ def parse_sphere(obj)
85
+ Object::Sphere.new(Point3.new(*obj["center"]), obj["radius"], material(obj["material"]))
86
+ end
87
+
88
+ def parse_moving_sphere(obj)
89
+ Object::MovingSphere.new(Point3.new(*obj["center1"]), Point3.new(*obj["center2"]), obj["radius"], material(obj["material"]))
90
+ end
91
+
54
92
  def material(name)
55
- raise ParserError, "unknown material #{name}" unless @materials.key?(name)
93
+ raise Error, "unknown material #{name}" unless @materials.key?(name)
56
94
 
57
95
  @materials[name]
58
96
  end
data/lib/rray/tracer.rb CHANGED
@@ -29,7 +29,7 @@ module Rray
29
29
 
30
30
  rec = scene.world.hit(r, 0.001..Float::INFINITY)
31
31
  if rec
32
- scattered = rec.mat.scatter(r, rec)
32
+ scattered = rec.material.scatter(r, rec)
33
33
  return Color.new(0.0, 0.0, 0.0) unless scattered
34
34
 
35
35
  return ray_color(scattered.ray, depth-1).multiply(scattered.attenuation)
data/lib/rray/util.rb CHANGED
@@ -6,7 +6,6 @@ module Rray
6
6
 
7
7
  # Returns a random real in [min,max).
8
8
  def self.random(min, max) = min + (max-min)*rand
9
- def self.sample_square = Vec3.new(rand - 0.5, rand - 0.5, 0.0)
10
9
 
11
10
  def self.linear_to_gamma(linear_component)
12
11
  return 0 unless linear_component > 0
data/lib/rray/vec3.rb CHANGED
@@ -6,6 +6,10 @@ module Rray
6
6
  @e = [x, y, z]
7
7
  end
8
8
 
9
+ def to_a
10
+ @e.dup
11
+ end
12
+
9
13
  def x = @e[0]
10
14
  def y = @e[1]
11
15
  def z = @e[2]
@@ -22,10 +26,15 @@ module Rray
22
26
  @e[2] = v
23
27
  end
24
28
 
25
- def -@ = self.class.new(-x, -y, -z)
26
- def [](i) = @e[i]
29
+ def -@
30
+ self.class.new(-x, -y, -z)
31
+ end
32
+
33
+ def [](i)
34
+ @e[i]
35
+ end
27
36
 
28
- def []=(i, v)
37
+ def []=(i, v)
29
38
  @e[i] = v
30
39
  end
31
40
 
@@ -104,13 +113,17 @@ module Rray
104
113
  r_out_perp.add(r_out_parallel)
105
114
  end
106
115
 
116
+ def to_s
117
+ "(#{x},#{y},#{z})"
118
+ end
119
+
107
120
  def self.random(min = 0.0, max = 1.0)
108
- Vec3.new(Util.random(min, max), Util.random(min, max), Util.random(min, max))
121
+ new(Util.random(min, max), Util.random(min, max), Util.random(min, max))
109
122
  end
110
123
 
111
124
  def self.random_in_unit_sphere
112
125
  loop do
113
- v = Vec3.random(-1.0, 1.0)
126
+ v = random(-1.0, 1.0)
114
127
  return v if v.length_squared < 1
115
128
  end
116
129
  end
@@ -128,9 +141,11 @@ module Rray
128
141
 
129
142
  def self.random_in_unit_disk
130
143
  loop do
131
- v = Vec3.new(Util.random(-1.0, 1.0), Util.random(-1.0, 1.0), 0.0)
144
+ v = new(Util.random(-1.0, 1.0), Util.random(-1.0, 1.0), 0.0)
132
145
  return v if v.length_squared < 1
133
146
  end
134
147
  end
148
+
149
+ def self.sample_square = new(rand - 0.5, rand - 0.5, 0.0)
135
150
  end
136
151
  end
data/lib/rray/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rray
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/rray.rb CHANGED
@@ -11,11 +11,14 @@ require_relative "rray/point3"
11
11
  require_relative "rray/color"
12
12
  require_relative "rray/ray"
13
13
  require_relative "rray/interval"
14
+ require_relative "rray/aabb"
14
15
  require_relative "rray/hit"
15
16
  require_relative "rray/scatter"
16
17
  require_relative "rray/object/base"
17
18
  require_relative "rray/object/sphere"
19
+ require_relative "rray/object/moving_sphere"
18
20
  require_relative "rray/object/group"
21
+ require_relative "rray/object/bvh"
19
22
  require_relative "rray/material/base"
20
23
  require_relative "rray/material/lambertian"
21
24
  require_relative "rray/material/metal"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rray
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danielle Smith
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-15 00:00:00.000000000 Z
11
+ date: 2024-05-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Simple raytracer written in ruby. Can be used a CLI tool or library.
14
14
  email:
@@ -21,6 +21,7 @@ files:
21
21
  - README.md
22
22
  - Rakefile
23
23
  - lib/rray.rb
24
+ - lib/rray/aabb.rb
24
25
  - lib/rray/camera.rb
25
26
  - lib/rray/color.rb
26
27
  - lib/rray/hit.rb
@@ -30,7 +31,9 @@ files:
30
31
  - lib/rray/material/lambertian.rb
31
32
  - lib/rray/material/metal.rb
32
33
  - lib/rray/object/base.rb
34
+ - lib/rray/object/bvh.rb
33
35
  - lib/rray/object/group.rb
36
+ - lib/rray/object/moving_sphere.rb
34
37
  - lib/rray/object/sphere.rb
35
38
  - lib/rray/point3.rb
36
39
  - lib/rray/ray.rb