rubytracer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Rakefile +7 -0
- data/lib/rubytracer/camera.rb +20 -0
- data/lib/rubytracer/colour.rb +88 -0
- data/lib/rubytracer/lights/ambient.rb +17 -0
- data/lib/rubytracer/lights/point.rb +46 -0
- data/lib/rubytracer/lights.rb +6 -0
- data/lib/rubytracer/material.rb +43 -0
- data/lib/rubytracer/scene.rb +26 -0
- data/lib/rubytracer/shapes/sphere.rb +30 -0
- data/lib/rubytracer/shapes.rb +5 -0
- data/lib/rubytracer/version.rb +3 -0
- data/lib/rubytracer/view.rb +24 -0
- data/lib/rubytracer.rb +11 -0
- data/rubytracer.gemspec +26 -0
- data/spec/spec_helper.rb +1 -0
- metadata +108 -0
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rubytracer
|
2
|
+
class Camera
|
3
|
+
def initialize(view, scene)
|
4
|
+
@view = view
|
5
|
+
@scene = scene
|
6
|
+
end
|
7
|
+
|
8
|
+
def colour_of_pixel(row, col)
|
9
|
+
ray = @view.eye_ray(row, col)
|
10
|
+
obj, t = @scene.intersect(ray)
|
11
|
+
if t == Float::INFINITY
|
12
|
+
Colour.new(0.6,0.6,0.6)
|
13
|
+
else
|
14
|
+
pos = ray.pos(t)
|
15
|
+
normal = obj.normal(pos)
|
16
|
+
obj.material.lit_colour(@scene, normal, -ray.dir, pos)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Rubytracer
|
2
|
+
class Colour
|
3
|
+
attr_reader :r, :g, :b
|
4
|
+
|
5
|
+
def initialize(r,g,b)
|
6
|
+
@r = r
|
7
|
+
@g = g
|
8
|
+
@b = b
|
9
|
+
end
|
10
|
+
|
11
|
+
def - other
|
12
|
+
Colour.new(@r - other.r, @g - other.g, @b - other.b)
|
13
|
+
end
|
14
|
+
|
15
|
+
def + other
|
16
|
+
Colour.new(@r + other.r, @g + other.g, @b + other.b)
|
17
|
+
end
|
18
|
+
|
19
|
+
def * other
|
20
|
+
case other
|
21
|
+
when Colour
|
22
|
+
Colour.new(@r * other.r, @g * other.g, @b * other.b)
|
23
|
+
else
|
24
|
+
Colour.new(@r * other, @g * other, @b * other)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def ** power
|
29
|
+
Colour.new(@r ** power, @g ** power, @b ** power)
|
30
|
+
end
|
31
|
+
|
32
|
+
def / scale
|
33
|
+
self * (1.0/scale)
|
34
|
+
end
|
35
|
+
|
36
|
+
def +@
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def -@
|
41
|
+
Colour.new(-@r, -@g, -@b)
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_int
|
45
|
+
[[[0, @r * 256].max, 255].min, [[0, @g * 256].max, 255].min, [[0, @b * 256].max, 255].min]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
class Fixnum
|
52
|
+
alias :times_without_rubytracer :'*'
|
53
|
+
|
54
|
+
def * other
|
55
|
+
case other
|
56
|
+
when Rubytracer::Colour
|
57
|
+
Rubytracer::Colour.new(self * other.r, self * other.g, self * other.b)
|
58
|
+
else
|
59
|
+
self.times_without_rubytracer(other)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Bignum
|
65
|
+
alias :times_without_rubytracer :'*'
|
66
|
+
|
67
|
+
def * other
|
68
|
+
case other
|
69
|
+
when Rubytracer::Colour
|
70
|
+
Rubytracer::Colour.new(self * other.r, self * other.g, self * other.b)
|
71
|
+
else
|
72
|
+
self.times_without_rubytracer(other)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Float
|
78
|
+
alias :times_without_rubytracer :'*'
|
79
|
+
|
80
|
+
def * other
|
81
|
+
case other
|
82
|
+
when Rubytracer::Colour
|
83
|
+
Rubytracer::Colour.new(self * other.r, self * other.g, self * other.b)
|
84
|
+
else
|
85
|
+
self.times_without_rubytracer(other)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubytracer/colour'
|
2
|
+
|
3
|
+
module Rubytracer
|
4
|
+
class AmbientLight
|
5
|
+
def initialize value
|
6
|
+
@value = value
|
7
|
+
end
|
8
|
+
|
9
|
+
def specular(normal, view_vector, point, scene)
|
10
|
+
return Colour.new(0,0,0)
|
11
|
+
end
|
12
|
+
|
13
|
+
def diffuse(normal, point, scene)
|
14
|
+
return @value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'geom3d'
|
2
|
+
|
3
|
+
module Rubytracer
|
4
|
+
class PointLight
|
5
|
+
def initialize(value, point)
|
6
|
+
@value = value
|
7
|
+
@point = point
|
8
|
+
end
|
9
|
+
|
10
|
+
def check_shadow(point, direction, distance, scene)
|
11
|
+
ray = Geom3d::Ray.new(point + direction * 0.00001, direction)
|
12
|
+
obj, alpha = scene.intersect(ray)
|
13
|
+
pos = ray.pos(alpha)
|
14
|
+
alpha < distance
|
15
|
+
end
|
16
|
+
|
17
|
+
def distance_loss(distance)
|
18
|
+
([0, 8 - distance].max / 8) ** 3
|
19
|
+
end
|
20
|
+
|
21
|
+
def specular(normal, view_vector, point, scene)
|
22
|
+
vector = @point - point
|
23
|
+
dir = vector.unit
|
24
|
+
dis = vector.length
|
25
|
+
|
26
|
+
if check_shadow(point, dir, dis, scene)
|
27
|
+
Colour.new(0,0,0)
|
28
|
+
else
|
29
|
+
d = (2 * view_vector.dot(normal) * normal - view_vector).unit
|
30
|
+
@value * distance_loss(dis) * [0, d.dot(dir)].max
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def diffuse(normal, point, scene)
|
35
|
+
vector = @point - point
|
36
|
+
dir = vector.unit
|
37
|
+
dis = vector.length
|
38
|
+
|
39
|
+
if check_shadow(point, dir, dis, scene)
|
40
|
+
Colour.new(0,0,0)
|
41
|
+
else
|
42
|
+
@value * distance_loss(dis) * [0, dir.dot(normal)].max
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Rubytracer
|
2
|
+
class Material
|
3
|
+
def initialize(options)
|
4
|
+
@d_colour = options[:diffuse_colour]
|
5
|
+
@s_colour = options[:specular_colour]
|
6
|
+
@shininess = options[:shininess]
|
7
|
+
end
|
8
|
+
|
9
|
+
def diffuse_colour(point, normal)
|
10
|
+
@d_colour || Colour.new(0,0,0)
|
11
|
+
end
|
12
|
+
|
13
|
+
def specular_colour(point, normal)
|
14
|
+
@s_colour || Colour.new(0,0,0)
|
15
|
+
end
|
16
|
+
|
17
|
+
def lit_colour(scene, normal, view_vector, point, n=0)
|
18
|
+
reflection = Colour.new(0,0,0)
|
19
|
+
|
20
|
+
#reflection += self.reflection(
|
21
|
+
#reflection += self.refraction(
|
22
|
+
|
23
|
+
scene.lighting.each do |light|
|
24
|
+
reflection += self.diffuse(point, normal, scene, light)
|
25
|
+
reflection += self.specular(point, normal, scene, view_vector, light)
|
26
|
+
end
|
27
|
+
|
28
|
+
return reflection
|
29
|
+
end
|
30
|
+
|
31
|
+
def diffuse(point, normal, scene, light)
|
32
|
+
self.diffuse_colour(point, normal) * light.diffuse(normal, point, scene)
|
33
|
+
end
|
34
|
+
|
35
|
+
def specular(point, normal, scene, view_vector, light)
|
36
|
+
if @shininess
|
37
|
+
self.specular_colour(point, normal) * (light.specular(normal, view_vector, point, scene) ** @shininess)
|
38
|
+
else
|
39
|
+
Colour.new(0,0,0)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Rubytracer
|
2
|
+
class Scene
|
3
|
+
attr_reader :lighting
|
4
|
+
|
5
|
+
def initialize(objects=[], lighting=[])
|
6
|
+
@objects = objects
|
7
|
+
@lighting = lighting
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_object(object)
|
11
|
+
@objects << object
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_light(light)
|
15
|
+
@lighting << light
|
16
|
+
end
|
17
|
+
|
18
|
+
def intersect(ray)
|
19
|
+
min = [nil, Float::INFINITY]
|
20
|
+
@objects.map { |object| [object, object.intersect(ray)[0]] }.each do |object, intersection|
|
21
|
+
min = [object, intersection] if intersection > 0 && intersection < min[1]
|
22
|
+
end
|
23
|
+
min
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Rubytracer
|
2
|
+
class Sphere
|
3
|
+
attr_reader :material
|
4
|
+
|
5
|
+
def initialize(center, radius, material)
|
6
|
+
@center = center
|
7
|
+
@radius = radius
|
8
|
+
@material = material
|
9
|
+
end
|
10
|
+
|
11
|
+
def normal(point)
|
12
|
+
(point - @center).unit
|
13
|
+
end
|
14
|
+
|
15
|
+
def intersect(ray)
|
16
|
+
q = @center - ray.start
|
17
|
+
v_dot_q = ray.dir.dot(q)
|
18
|
+
square_diffs = q.dot(q) - @radius ** 2
|
19
|
+
discrim = v_dot_q ** 2 - square_diffs
|
20
|
+
if discrim >= 0
|
21
|
+
root = Math.sqrt(discrim)
|
22
|
+
t0 = v_dot_q - root
|
23
|
+
t1 = v_dot_q + root
|
24
|
+
[t0, t1]
|
25
|
+
else
|
26
|
+
[Float::INFINITY, -Float::INFINITY] # May not be portable
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'geom3d'
|
2
|
+
|
3
|
+
module Rubytracer
|
4
|
+
class View
|
5
|
+
def initialize(view_point, look_at_point, view_up, h_fov, height, width, multi)
|
6
|
+
view_direction = (look_at_point - view_point).unit
|
7
|
+
view_up = view_up - view_direction * view_up.dot(view_direction)
|
8
|
+
spacing = 2 * Math.tan(h_fov * Math::PI / 360) / width
|
9
|
+
|
10
|
+
@point = view_point
|
11
|
+
@multi = multi
|
12
|
+
@y_vector = -spacing * view_up.unit
|
13
|
+
@x_vector = spacing * view_up.unit.cross(view_direction.unit).unit
|
14
|
+
@top_left = (view_point + view_direction) - (@y_vector * height / 2 + @x_vector * width / 2)
|
15
|
+
end
|
16
|
+
|
17
|
+
def eye_ray(row, col)
|
18
|
+
dy = @y_vector * (row + 0.5)
|
19
|
+
dx = @x_vector * (col + 0.5)
|
20
|
+
point = @top_left + dy + dx
|
21
|
+
Geom3d::Ray.new(@point, point - @point)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/rubytracer.rb
ADDED
data/rubytracer.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rubytracer/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rubytracer"
|
7
|
+
s.version = Rubytracer::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Nemo157 (Wim Looman)"]
|
10
|
+
s.email = ["ghostunderscore@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{A simple pure ruby raytracer library}
|
13
|
+
s.description = %q{A simple pure ruby raytracer library}
|
14
|
+
s.licenses = ["Apache License 2.0"]
|
15
|
+
|
16
|
+
s.rubyforge_project = "rubytracer"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_runtime_dependency 'geom3d'
|
24
|
+
|
25
|
+
s.add_development_dependency 'rspec', '~>2.3.0'
|
26
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rspec'
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubytracer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Nemo157 (Wim Looman)
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-13 00:00:00 +13:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: geom3d
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rspec
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 2
|
43
|
+
- 3
|
44
|
+
- 0
|
45
|
+
version: 2.3.0
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
description: A simple pure ruby raytracer library
|
49
|
+
email:
|
50
|
+
- ghostunderscore@gmail.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- Gemfile
|
60
|
+
- Rakefile
|
61
|
+
- lib/rubytracer.rb
|
62
|
+
- lib/rubytracer/camera.rb
|
63
|
+
- lib/rubytracer/colour.rb
|
64
|
+
- lib/rubytracer/lights.rb
|
65
|
+
- lib/rubytracer/lights/ambient.rb
|
66
|
+
- lib/rubytracer/lights/point.rb
|
67
|
+
- lib/rubytracer/material.rb
|
68
|
+
- lib/rubytracer/scene.rb
|
69
|
+
- lib/rubytracer/shapes.rb
|
70
|
+
- lib/rubytracer/shapes/sphere.rb
|
71
|
+
- lib/rubytracer/version.rb
|
72
|
+
- lib/rubytracer/view.rb
|
73
|
+
- rubytracer.gemspec
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
has_rdoc: true
|
76
|
+
homepage: ""
|
77
|
+
licenses:
|
78
|
+
- Apache License 2.0
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
version: "0"
|
100
|
+
requirements: []
|
101
|
+
|
102
|
+
rubyforge_project: rubytracer
|
103
|
+
rubygems_version: 1.3.7
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: A simple pure ruby raytracer library
|
107
|
+
test_files:
|
108
|
+
- spec/spec_helper.rb
|