rubytracer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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