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 ADDED
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in Geom3d.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -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,6 @@
1
+ %w{
2
+ rubytracer/lights/ambient
3
+ rubytracer/lights/point
4
+ }.each do |file|
5
+ require file
6
+ 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,5 @@
1
+ %w{
2
+ rubytracer/shapes/sphere
3
+ }.each do |file|
4
+ require file
5
+ end
@@ -0,0 +1,3 @@
1
+ module Rubytracer
2
+ VERSION = "0.1.0"
3
+ 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
@@ -0,0 +1,11 @@
1
+ %w{
2
+ rubytracer/scene
3
+ rubytracer/view
4
+ rubytracer/camera
5
+ rubytracer/colour
6
+ rubytracer/material
7
+ rubytracer/shapes
8
+ rubytracer/lights
9
+ }.each do |file|
10
+ require file
11
+ end
@@ -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
@@ -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