mittsu 0.2.4 → 0.3.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: db458484a3c4620067a0a3d7c58751e0a7588cbb4320f10be9ed49441db5ba07
4
- data.tar.gz: 8af94bffbd0c624f0b5e676e9da2b5e72de09eaf3f921d9650617b56e84fad5d
3
+ metadata.gz: 1d75b0ef6c6615fff22f50ab9f3bc438e5c2631d5924f30da913df6403d5ccd0
4
+ data.tar.gz: 4656d50526e5be69dd19f3f0de87b4f93de5ad0a2e664b6277b023b885d7c3a0
5
5
  SHA512:
6
- metadata.gz: f45a750a1557b6f9fdbe46a1cb652b9d6e731294da4d00af0602ec2d64f0fbb47c63dba9ec249f94c006ebbe76066d67dad50c6c94ca066c0d376e9dd38f67ee
7
- data.tar.gz: d3f6931cf6301e53bcbc2296213fc1da27996f46d6211a4d949af16ecc1489cd2e909a5ce6b934b6c3cad55ad21beb81c71c92cea63625146d8b1a38a9d99b1d
6
+ metadata.gz: 4093db783cef7214c92fa5ce723cf84466a4dcd30d1e7a8fe6c5b9ff41f4be13d04eaeb072e30e6e039191d410303adf47c55288429439412e746ba300e05918
7
+ data.tar.gz: e3bafbb95cff8e606f36e6e456314a75cbfc9c0284022ef73258d40316918fd87dce5b11b21aa1b25802a071b91b413df53de8220f1294eadf892600f79868fd
@@ -1,5 +1,6 @@
1
1
  require 'securerandom'
2
2
  require 'mittsu'
3
+ require 'securerandom'
3
4
 
4
5
  module Mittsu
5
6
  class Geometry
@@ -19,6 +20,8 @@ module Mittsu
19
20
 
20
21
  @id = (@@id ||= 1).tap { @@id += 1 }
21
22
 
23
+ @uuid = SecureRandom.uuid
24
+
22
25
  @name = ''
23
26
  @type = 'Geometry'
24
27
 
@@ -105,7 +108,7 @@ module Mittsu
105
108
  }
106
109
  if indices
107
110
  draw_calls = geometry.draw_calls
108
- if !draw_calls.length.empty?
111
+ if !draw_calls.empty?
109
112
  draw_calls.each do |draw_call|
110
113
  start = draw_call.start
111
114
  count = draw_call.count
@@ -119,7 +122,7 @@ module Mittsu
119
122
  end
120
123
  else
121
124
  indices.each_slice(3).with_index do |index|
122
- add_face(*index)
125
+ add_face[*index]
123
126
  end
124
127
  end
125
128
  else
@@ -130,10 +133,10 @@ module Mittsu
130
133
  end
131
134
  end
132
135
  self.compute_face_normals
133
- if geometry.boundingBox
136
+ if geometry.bounding_box
134
137
  @bounding_box = geometry.bounding_box.clone
135
138
  end
136
- if geometry.boundingSphere
139
+ if geometry.bounding_sphere
137
140
  @bounding_sphere = geometry.bounding_sphere.clone
138
141
  end
139
142
  self
@@ -160,12 +163,12 @@ module Mittsu
160
163
  end
161
164
  end
162
165
 
163
- def compute_vertex_normals(area_weigted)
166
+ def compute_vertex_normals(area_weighted = false)
164
167
  vertices = Array.new(@vertices.length)
165
168
  @vertices.length.times do |v|
166
169
  vertices[v] = Mittsu::Vector3.new
167
170
  end
168
- if area_weigted
171
+ if area_weighted
169
172
  # vertex normals weighted by triangle areas
170
173
  # http:#www.iquilezles.org/www/articles/normals/normals.htm
171
174
  cb = Mittsu::Vector3.new, ab = Mittsu::Vector3.new
@@ -1,2 +1,15 @@
1
1
  require 'mittsu/extras/geometries/box_geometry'
2
2
  require 'mittsu/extras/geometries/sphere_geometry'
3
+ require 'mittsu/extras/geometries/ring_geometry'
4
+ require 'mittsu/extras/geometries/circle_geometry'
5
+ require 'mittsu/extras/geometries/cylinder_geometry'
6
+ require 'mittsu/extras/geometries/dodecahedron_geometry'
7
+ require 'mittsu/extras/geometries/icosahedron_geometry'
8
+ require 'mittsu/extras/geometries/octahedron_geometry'
9
+ require 'mittsu/extras/geometries/tetrahedron_geometry'
10
+ require 'mittsu/extras/geometries/plane_buffer_geometry'
11
+ require 'mittsu/extras/geometries/plane_geometry'
12
+ require 'mittsu/extras/geometries/torus_geometry'
13
+ require 'mittsu/extras/geometries/torus_knot_geometry'
14
+ require 'mittsu/extras/geometries/parametric_geometry'
15
+ require 'mittsu/extras/geometries/lathe_geometry'
@@ -0,0 +1,48 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+
4
+ module Mittsu
5
+ class CircleGeometry < Geometry
6
+ def initialize(radius = 50.0, segments = 8, theta_start = 0.0, theta_length = (Math::PI * 2.0))
7
+ super()
8
+
9
+ @type = 'CircleGeometry'
10
+
11
+ @parameters = {
12
+ radius: radius,
13
+ segments: segments,
14
+ theta_start: theta_start,
15
+ theta_length: theta_length
16
+ }
17
+
18
+ segments = [3, segments].max
19
+
20
+ center = Vector3.new
21
+ center_uv = Vector2.new(0.5, 0.5)
22
+
23
+ @vertices << center
24
+ uvs = [center_uv]
25
+
26
+ for i in 0..segments do
27
+ vertex = Vector3.new
28
+ segment = theta_start + i.to_f / segments.to_f * theta_length
29
+
30
+ vertex.x = radius * Math.cos(segment)
31
+ vertex.y = radius * Math.sin(segment)
32
+
33
+ @vertices << vertex
34
+ uvs << Vector2.new((vertex.x / radius + 1.0) / 2.0, (vertex.y / radius + 1.0) / 2.0)
35
+ end
36
+
37
+ n = Vector3.new
38
+
39
+ for i in 1..segments do
40
+ @faces << Face3.new(i, i + 1, 0, [n.clone, n.clone, n.clone])
41
+ @face_vertex_uvs[0] << [uvs[i].clone, uvs[i + 1].clone, center_uv.clone]
42
+ end
43
+
44
+ compute_face_normals
45
+ @bounding_sphere = Sphere.new(Vector3.new, radius)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,145 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+
4
+ module Mittsu
5
+ class CylinderGeometry < Geometry
6
+ def initialize(radius_top = 20.0, radius_bottom = 20.0, height = 100.0, radial_segments = 8, height_segments = 1, open_ended = false, theta_start = 0.0, theta_length = (Math::PI * 2.0))
7
+ super()
8
+
9
+ @type = 'CylinderGeometry'
10
+
11
+ @parameters = {
12
+ radius_top: radius_top,
13
+ radius_bottom: radius_bottom,
14
+ height: height,
15
+ radial_segments: radial_segments,
16
+ height_segments: height_segments,
17
+ open_ended: open_ended,
18
+ theta_start: theta_start,
19
+ theta_length: theta_length
20
+ }
21
+
22
+ height_half = height / 2.0
23
+
24
+ index_rows = []
25
+ uv_rows = []
26
+
27
+ for y in 0..height_segments do
28
+ index_row = []
29
+ uv_row = []
30
+
31
+ v = y.to_f / height_segments.to_f
32
+ radius = v * (radius_bottom - radius_top) + radius_top
33
+
34
+ for x in 0..radial_segments do
35
+ u = x.to_f / radial_segments
36
+
37
+ vertex = Vector3.new
38
+ vertex.x = radius * Math.sin(u * theta_length + theta_start)
39
+ vertex.y = -v * height + height_half
40
+ vertex.z = radius * Math.cos(u * theta_length + theta_start)
41
+
42
+ @vertices << vertex
43
+
44
+ index_row << (vertices.length - 1)
45
+ uv_row << Vector2.new(u, 1.0 - v)
46
+ end
47
+
48
+ index_rows << index_row
49
+ uv_rows << uv_row
50
+ end
51
+
52
+ tan_theta = (radius_bottom - radius_top) / height
53
+
54
+ na = nil
55
+ nb = nil
56
+
57
+ for x in 0...radial_segments do
58
+ if radius_top != 0
59
+ na = @vertices[index_rows[0][x]].clone
60
+ nb = @vertices[index_rows[0][x + 1]].clone
61
+ else
62
+ na = @vertices[index_rows[1][x]].clone
63
+ nb = @vertices[index_rows[1][x + 1]].clone
64
+ end
65
+
66
+ na.y = Math.sqrt(na.x * na.x + na.z * na.z) * tan_theta
67
+ na.normalize
68
+
69
+ nb.y = Math.sqrt(nb.x * nb.x + nb.z * nb.z) * tan_theta
70
+ nb.normalize
71
+
72
+ for y in 0...height_segments do
73
+ v1 = index_rows[y][x]
74
+ v2 = index_rows[y + 1][x]
75
+ v3 = index_rows[y + 1][x + 1]
76
+ v4 = index_rows[y][x + 1]
77
+
78
+ n1 = na.clone
79
+ n2 = na.clone
80
+ n3 = nb.clone
81
+ n4 = nb.clone
82
+
83
+ uv1 = uv_rows[y][x].clone
84
+ uv2 = uv_rows[y + 1][x].clone
85
+ uv3 = uv_rows[y + 1][x + 1].clone
86
+ uv4 = uv_rows[y][x + 1].clone
87
+
88
+ @faces << Face3.new(v1, v2, v4, [n1, n2, n4])
89
+ @face_vertex_uvs[0] << [uv1, uv2, uv4]
90
+
91
+ @faces << Face3.new(v2, v3, v4, [n2.clone, n3, n4.clone])
92
+ @face_vertex_uvs[0] << [uv2.clone, uv3, uv4.clone]
93
+ end
94
+ end
95
+
96
+ # top cap
97
+
98
+ if !open_ended && radius_top > 0.0
99
+ @vertices << Vector3.new(0, height_half, 0)
100
+
101
+ for x in 0...radial_segments do
102
+ v1 = index_rows[0][x]
103
+ v2 = index_rows[0][x + 1]
104
+ v3 = @vertices.length - 1
105
+
106
+ n1 = Vector3.new(0, 1, 0)
107
+ n2 = Vector3.new(0, 1, 0)
108
+ n3 = Vector3.new(0, 1, 0)
109
+
110
+ uv1 = uv_rows[0][x].clone
111
+ uv2 = uv_rows[0][x + 1].clone
112
+ uv3 = Vector2.new(uv2.x, 0)
113
+
114
+ @faces << Face3.new(v1, v2, v3, [n1, n2, n3])
115
+ @face_vertex_uvs[0] << [uv1, uv2, uv3]
116
+ end
117
+ end
118
+
119
+ # bottom cap
120
+
121
+ if !open_ended && radius_bottom > 0.0
122
+ @vertices << Vector3.new(0, -height_half, 0)
123
+
124
+ for x in 0...radial_segments do
125
+ v1 = index_rows[height_segments][x + 1]
126
+ v2 = index_rows[height_segments][x]
127
+ v3 = @vertices.length - 1
128
+
129
+ n1 = Vector3.new(0, -1, 0)
130
+ n2 = Vector3.new(0, -1, 0)
131
+ n3 = Vector3.new(0, -1, 0)
132
+
133
+ uv1 = uv_rows[height_segments][x].clone
134
+ uv2 = uv_rows[height_segments][x + 1].clone
135
+ uv3 = Vector2.new(uv2.x, 0)
136
+
137
+ @faces << Face3.new(v1, v2, v3, [n1, n2, n3])
138
+ @face_vertex_uvs[0] << [uv1, uv2, uv3]
139
+ end
140
+ end
141
+
142
+ compute_face_normals
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,56 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+ require 'mittsu/extras/geometries/polyhedron_geometry'
4
+
5
+ module Mittsu
6
+ class DodecahedronGeometry < PolyhedronGeometry
7
+ def initialize(radius = 1.0, detail = 0)
8
+ t = (1.0 + Math.sqrt(5.0)) / 2.0
9
+ r = 1.0 / t
10
+
11
+ vertices = [
12
+ # (±1, ±1, ±1)
13
+ -1, -1, -1, -1, -1, 1,
14
+ -1, 1, -1, -1, 1, 1,
15
+ 1, -1, -1, 1, -1, 1,
16
+ 1, 1, -1, 1, 1, 1,
17
+
18
+ # (0, ±1/φ, ±φ)
19
+ 0, -r, -t, 0, -r, t,
20
+ 0, r, -t, 0, r, t,
21
+
22
+ # (±1/φ, ±φ, 0)
23
+ -r, -t, 0, -r, t, 0,
24
+ r, -t, 0, r, t, 0,
25
+
26
+ # (±φ, 0, ±1/φ)
27
+ -t, 0, -r, t, 0, -r,
28
+ -t, 0, r, t, 0, r
29
+ ]
30
+
31
+ indices = [
32
+ 3, 11, 7, 3, 7, 15, 3, 15, 13,
33
+ 7, 19, 17, 7, 17, 6, 7, 6, 15,
34
+ 17, 4, 8, 17, 8, 10, 17, 10, 6,
35
+ 8, 0, 16, 8, 16, 2, 8, 2, 10,
36
+ 0, 12, 1, 0, 1, 18, 0, 18, 16,
37
+ 6, 10, 2, 6, 2, 13, 6, 13, 15,
38
+ 2, 16, 18, 2, 18, 3, 2, 3, 13,
39
+ 18, 1, 9, 18, 9, 11, 18, 11, 3,
40
+ 4, 14, 12, 4, 12, 0, 4, 0, 8,
41
+ 11, 9, 5, 11, 5, 19, 11, 19, 7,
42
+ 19, 5, 14, 19, 14, 4, 19, 4, 17,
43
+ 1, 12, 14, 1, 14, 5, 1, 5, 9
44
+ ]
45
+
46
+ super(vertices, indices, radius, detail)
47
+
48
+ @type = 'DodecahedronGeometry'
49
+
50
+ @parameters = {
51
+ radius: radius,
52
+ detail: detail
53
+ }
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,33 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+ require 'mittsu/extras/geometries/polyhedron_geometry'
4
+
5
+ module Mittsu
6
+ class IcosahedronGeometry < PolyhedronGeometry
7
+ def initialize(radius = 1.0, detail = 0)
8
+ t = (1.0 + Math.sqrt(5)) / 2.0
9
+
10
+ vertices = [
11
+ - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,
12
+ 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,
13
+ t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1
14
+ ]
15
+
16
+ indices = [
17
+ 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
18
+ 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
19
+ 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
20
+ 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
21
+ ]
22
+
23
+ super(vertices, indices, radius, detail)
24
+
25
+ @type = 'IcosahedronGeometry'
26
+
27
+ @parameters = {
28
+ radius: radius,
29
+ detail: detail
30
+ }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,78 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+
4
+ module Mittsu
5
+ class LatheGeometry < Geometry
6
+ def initialize(points, segments = 12, phi_start = 0.0, phi_length = (Math::PI * 2.0))
7
+ super()
8
+
9
+ @type = 'LatheGeometry'
10
+
11
+ @parameters = {
12
+ points: points,
13
+ segments: segments,
14
+ phi_start: phi_start,
15
+ phi_length: phi_length
16
+ }
17
+
18
+ inverse_point_length = 1.0 / (points.length.to_f - 1.0)
19
+ inverse_segments = 1.0 / segments.to_f
20
+
21
+ for i in 0..segments do
22
+ phi = phi_start + i.to_f * inverse_segments * phi_length
23
+
24
+ c = Math.cos(phi)
25
+ s = Math.sin(phi)
26
+
27
+ for j in 0...points.length do
28
+ pt = points[j]
29
+
30
+ vertex = Vector3.new
31
+
32
+ vertex.x = c * pt.x
33
+ vertex.y = pt.y
34
+ vertex.z = s * pt.x
35
+
36
+ @vertices << vertex
37
+ end
38
+ end
39
+
40
+ np = points.length
41
+
42
+ for i in 0...segments do
43
+ for j in 0...(points.length - 1) do
44
+ base = j + np * i
45
+ a = base
46
+ b = base + np
47
+ c = base + 1 + np
48
+ d = base + 1
49
+
50
+ u0 = i.to_f * inverse_segments
51
+ v0 = j.to_f * inverse_point_length
52
+ u1 = u0 + inverse_segments
53
+ v1 = v0 + inverse_point_length
54
+
55
+ @faces << Face3.new(a, b, d)
56
+
57
+ @face_vertex_uvs[0] << [
58
+ Vector2.new(u0, v0),
59
+ Vector2.new(u1, v0),
60
+ Vector2.new(u0, v1)
61
+ ]
62
+
63
+ @faces << Face3.new(b, c, d)
64
+
65
+ @face_vertex_uvs[0] << [
66
+ Vector2.new(u1, v0),
67
+ Vector2.new(u1, v1),
68
+ Vector2.new(u0, v1)
69
+ ]
70
+ end
71
+ end
72
+
73
+ merge_vertices
74
+ compute_face_normals
75
+ compute_vertex_normals
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,26 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+ require 'mittsu/extras/geometries/polyhedron_geometry'
4
+
5
+ module Mittsu
6
+ class OctahedronGeometry < PolyhedronGeometry
7
+ def initialize(radius = 1.0, detail = 0)
8
+ vertices = [
9
+ 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0,- 1, 0, 0, 0, 1, 0, 0,- 1
10
+ ]
11
+
12
+ indices = [
13
+ 0, 2, 4, 0, 4, 3, 0, 3, 5, 0, 5, 2, 1, 2, 5, 1, 5, 3, 1, 3, 4, 1, 4, 2
14
+ ]
15
+
16
+ super(vertices, indices, radius, detail)
17
+
18
+ @type = 'OctahedronGeometry'
19
+
20
+ @parameters = {
21
+ radius: radius,
22
+ detail: detail
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,92 @@
1
+ module Mittsu
2
+ class ParametricBufferGeometry < BufferGeometry
3
+ EPS = 0.00001
4
+
5
+ def initialize(func, slices, stacks)
6
+ super()
7
+
8
+ @type = 'ParametricBufferGeometry'
9
+
10
+ @parameters = {
11
+ func: func,
12
+ slices: slices,
13
+ stacks: stacks
14
+ }
15
+
16
+ # buffers
17
+
18
+ indices = []
19
+ vertices = []
20
+ normals = []
21
+ uvs = []
22
+
23
+ normal = Vector3.new
24
+
25
+ p0 = Vector3.new
26
+ p1 = Vector3.new
27
+
28
+ pu = Vector3.new
29
+ pv = Vector3.new
30
+
31
+ # generate vertices, normals, and uvs
32
+
33
+ slice_count = slices + 1
34
+
35
+ for i in 0..stacks do
36
+ v = i.to_f / stacks.to_f
37
+
38
+ for j in 0..slices do
39
+ u = j.to_f / slices.to_f
40
+
41
+ # vertex
42
+ func.call(u, v, p0)
43
+ vertices += p0.elements
44
+
45
+ # normal
46
+
47
+ # approximate tangent vectors via finite differences
48
+ if u - EPS >= 0
49
+ func.call(u - EPS, v, p1)
50
+ pu.sub_vectors(p0, p1)
51
+ else
52
+ func.call(u + EPS, v, p1)
53
+ pu.sub_vectors(p1, p0)
54
+ end
55
+
56
+ if v - EPS >= 0
57
+ func.call(u, v - EPS, p1)
58
+ pv.sub_vectors(p0, p1)
59
+ else
60
+ func.call(u, v + EPS, p1)
61
+ pv.sub_vectors(p1, p0)
62
+ end
63
+
64
+ # cross product of tangent vectors returns surface normal
65
+ normal.cross_vectors(pu, pv).normalize
66
+ normals += normal.elements
67
+
68
+ # uv
69
+ uvs << u << v
70
+ end
71
+ end
72
+
73
+ for i in 0...stacks do
74
+ for j in 0...slices do
75
+ a = i * slice_count + j
76
+ b = i * slice_count + j + 1
77
+ c = (i + 1) * slice_count + j + 1
78
+ d = (i + 1) * slice_count + j
79
+
80
+ # faces one and two
81
+ indices << a << b << d
82
+ indices << b << c << d
83
+ end
84
+ end
85
+
86
+ self[:index] = BufferAttribute.new(indices, 1)
87
+ self[:position] = BufferAttribute.new(vertices, 3)
88
+ self[:normal] = BufferAttribute.new(normals, 3)
89
+ self[:uv] = BufferAttribute.new(uvs, 2)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,93 @@
1
+ require 'mittsu/extras/geometries/parametric_buffer_geometry'
2
+
3
+ module Mittsu
4
+ class ParametricGeometry < Geometry
5
+ def initialize(func, slices, stacks)
6
+ super()
7
+
8
+ @type = 'ParametricGeometry'
9
+
10
+ @parameters = {
11
+ func: func,
12
+ slices: slices,
13
+ stacks: stacks
14
+ }
15
+
16
+ from_buffer_geometry(ParametricBufferGeometry.new(func, slices, stacks))
17
+ merge_vertices
18
+ end
19
+
20
+ def self.klein
21
+ -> (v, u, target = Vector3.new) {
22
+ u *= Math::PI
23
+ v *= 2.0 * Math::PI
24
+
25
+ u = u * 2.0
26
+ x = nil
27
+ y = nil
28
+ z = nil
29
+
30
+ if u < Math::PI
31
+ x = 3.0 * Math.cos(u) * (1.0 + Math.sin(u)) + (2.0 * (1.0 - Math.cos(u) / 2.0)) * Math.cos(u) * Math.cos(v)
32
+ z = -8.0 * Math.sin(u) - 2.0 * (1.0 - Math.cos(u) / 2.0) * Math.sin(u) * Math.cos(v)
33
+ else
34
+ x = 3.0 * Math.cos(u) * (1.0 + Math.sin(u)) + (2.0 * (1.0 - Math.cos(u) / 2.0)) * Math.cos(v + Math::PI)
35
+ z = -8.0 * Math.sin(u)
36
+ end
37
+
38
+ y = -2.0 * (1.0 - Math.cos(u) / 2.0) * Math.sin(v)
39
+
40
+ target.set(x, y, z)
41
+ }
42
+ end
43
+
44
+ def self.plane(width, height)
45
+ -> (u, v, target = Vector3.new) {
46
+ x = u.to_f * width.to_f
47
+ y = 0.0
48
+ z = v.to_f * height.to_f
49
+
50
+ target.set(x, y, z)
51
+ }
52
+ end
53
+
54
+ def self.mobius
55
+ -> (u, t, target = Vector3.new) {
56
+ # flat mobius strip
57
+ # http://www.wolframalpha.com/input/?i=M%C3%B6bius+strip+parametric+equations&lk=1&a=ClashPrefs_*Surface.MoebiusStrip.SurfaceProperty.ParametricEquations-
58
+ u = u - 0.5
59
+ v = 2.0 * Math::PI * t
60
+
61
+ a = 2.0
62
+
63
+ x = Math.cos(v) * (a + u * Math.cos(v / 2.0))
64
+ y = Math.sin(v) * (a + u * Math.cos(v / 2.0))
65
+ z = u * Math.sin(v / 2)
66
+
67
+ target.set(x, y, z)
68
+ }
69
+ end
70
+
71
+ def self.mobius3d
72
+ -> (u, t, target = Vector3.new) {
73
+ # volumetric mobius strip
74
+
75
+ u *= Math::PI
76
+ t *= 2.0 * Math::PI
77
+
78
+ u = u * 2.0
79
+ phi = u / 2.0
80
+ major = 2.25
81
+ a = 0.125
82
+ b = 0.65
83
+
84
+ x = a * Math.cos(t) * Math.cos(phi) - b * Math.sin(t) * Math.sin(phi)
85
+ z = a * Math.cos(t) * Math.sin(phi) + b * Math.sin(t) * Math.cos(phi)
86
+ y = (major + x) * Math.sin(u)
87
+ x = (major + x) * Math.cos(u)
88
+
89
+ target.set(x, y, z)
90
+ }
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,81 @@
1
+ module Mittsu
2
+ class PlaneBufferGeometry < BufferGeometry
3
+ def initialize(width, height, width_segments = 1, height_segments = 1)
4
+ super()
5
+
6
+ @type = 'PlaneBufferGeometry'
7
+
8
+ @parameters = {
9
+ width: width,
10
+ height: height,
11
+ width_segments: width_segments,
12
+ height_segments: height_segments
13
+ }
14
+
15
+ width_half = width / 2.0
16
+ height_half = height / 2.0
17
+
18
+ grid_x = width_segments || 1
19
+ grid_y = height_segments || 1
20
+
21
+ grid_x1 = grid_x + 1
22
+ grid_y1 = grid_y + 1
23
+
24
+ segment_width = width.to_f / grid_x.to_f
25
+ segment_height = height.to_f / grid_y.to_f
26
+
27
+ vertices = Array.new(grid_x1 * grid_y1 * 3) # Float32Array
28
+ normals = Array.new(grid_x1 * grid_y1 * 3) #Float32Array
29
+ uvs = Array.new(grid_x1 * grid_y1 * 2) # Float32Array
30
+
31
+ offset = 0
32
+ offset2 = 0
33
+
34
+ for iy in 0...grid_y1 do
35
+ y = iy.to_f * segment_height - height_half
36
+ for ix in 0...grid_x1 do
37
+ x = ix.to_f * segment_width - width_half
38
+
39
+ vertices[offset] = x
40
+ vertices[offset + 1] = -y
41
+
42
+ normals[offset + 2] = 1.0
43
+
44
+ uvs[offset2] = ix.to_f / grid_x.to_f
45
+ uvs[offset2 + 1] = 1.0 - (iy.to_f / grid_y.to_f)
46
+
47
+ offset += 3
48
+ offset2 += 2
49
+ end
50
+ end
51
+
52
+ offset = 0
53
+
54
+ indices = Array.new(grid_x * grid_y * 6) # ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )
55
+
56
+ for iy in 0...grid_y do
57
+ for ix in 0...grid_x do
58
+ a = ix + grid_x1 * iy
59
+ b = ix + grid_x1 * (iy + 1)
60
+ c = (ix + 1) + grid_x1 * (iy + 1)
61
+ d = (ix + 1) + grid_x1 * iy
62
+
63
+ indices[offset ] = a
64
+ indices[offset + 1] = b
65
+ indices[offset + 2] = d
66
+
67
+ indices[offset + 3] = b
68
+ indices[offset + 4] = c
69
+ indices[offset + 5] = d
70
+
71
+ offset += 6
72
+ end
73
+ end
74
+
75
+ self[:index] = BufferAttribute.new(indices, 1)
76
+ self[:position] = BufferAttribute.new(vertices, 3)
77
+ self[:normal] = BufferAttribute.new(normals, 3)
78
+ self[:uv] = BufferAttribute.new(uvs, 2)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,22 @@
1
+ require 'mittsu/extras/geometries/plane_buffer_geometry'
2
+
3
+ module Mittsu
4
+ class PlaneGeometry < Geometry
5
+ def initialize(width, height, width_segments = 1, height_segments = 1)
6
+ puts 'Mittsu::PlaneGeometry: Consider using Mittsu::PlaneBufferGeometry for lower memory footprint.'
7
+
8
+ super()
9
+
10
+ @type = 'PlaneGeometry'
11
+
12
+ @parameters = {
13
+ width: width,
14
+ height: height,
15
+ width_segments: width_segments,
16
+ height_segments: height_segments
17
+ }
18
+
19
+ from_buffer_geometry(PlaneBufferGeometry.new(width, height, width_segments, height_segments))
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,168 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+
4
+ module Mittsu
5
+ class PolyhedronGeometry < Geometry
6
+ def initialize(vertices, indices, radius = 1.0, detail = 0)
7
+ super()
8
+
9
+ @type = 'PolyhedronGeometry'
10
+
11
+ @parameters = {
12
+ vertices: vertices,
13
+ indices: indices,
14
+ radius: radius,
15
+ detail: detail
16
+ }
17
+
18
+ for i in (0...vertices.length).step(3) do
19
+ prepare(Vector3.new(vertices[i], vertices[i + 1], vertices[i + 2]))
20
+ end
21
+
22
+ faces = []
23
+
24
+ i = 0
25
+ j = 0
26
+ while i < indices.length do
27
+ v1 = @vertices[indices[i]]
28
+ v2 = @vertices[indices[i + 1]]
29
+ v3 = @vertices[indices[i + 2]]
30
+ binding.irb if v1.nil? || v2.nil? || v3.nil?
31
+
32
+ faces[j] = Face3.new(v1.index, v2.index, v3.index, [v1.clone, v2.clone, v3.clone])
33
+
34
+ i += 3
35
+ j += 1
36
+ end
37
+
38
+ @centroid = Vector3.new
39
+
40
+ for i in 0...faces.length do
41
+ subdivide(faces[i], detail)
42
+ end
43
+
44
+ # Handle case when face straddles the seam
45
+
46
+ @face_vertex_uvs[0].each do |uv0, uv1, uv2|
47
+ x0 = uv0.x
48
+ x1 = uv1.x
49
+ x2 = uv2.x
50
+
51
+ max = [x0, x1, x2].max
52
+ min = [x0, x1, x2].min
53
+
54
+ if max > 0.9 && min < 0.1 # 0.9 is somewhat arbitrary
55
+ uv0.x += 1.0 if x0 < 0.2
56
+ uv1.x += 1.0 if x1 < 0.2
57
+ uv2.x += 1.0 if x2 < 0.2
58
+ end
59
+ end
60
+
61
+ # Apply radius
62
+
63
+ @vertices.each do |v|
64
+ v.multiply_scalar(radius)
65
+ end
66
+
67
+ merge_vertices
68
+
69
+ compute_face_normals
70
+ @bounding_sphere = Sphere.new(Vector3.new, radius)
71
+ end
72
+
73
+ private
74
+
75
+ # Project vector onto sphere's surface
76
+ def prepare(vector)
77
+ vertex = vector.normalize.clone
78
+ vertex.index = @vertices.push(vertex).length - 1
79
+
80
+ # Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle.
81
+ u = azimuth(vector) / 2.0 / Math::PI + 0.5
82
+ v = inclination(vector) / Math::PI + 0.5
83
+ vertex.uv = Vector2.new(u, 1.0 - v)
84
+
85
+ vertex
86
+ end
87
+
88
+ # Approximate a curved face with recursively sub-divided triangles.
89
+ def make(v1, v2, v3)
90
+ face = Face3.new(v1.index, v2.index, v3.index, [v1.clone, v2.clone, v3.clone])
91
+ @faces << face
92
+
93
+ @centroid.copy(v1).add(v2).add(v3).divide_scalar(3)
94
+
95
+ azi = azimuth(@centroid)
96
+
97
+ @face_vertex_uvs[0] << [
98
+ correct_uv(v1.uv, v1, azi),
99
+ correct_uv(v2.uv, v2, azi),
100
+ correct_uv(v3.uv, v3, azi)
101
+ ]
102
+ end
103
+
104
+ # Analytically subdivide a face to the required detail level.
105
+ def subdivide(face, detail)
106
+ cols = 2.0 ** detail
107
+ a = prepare(@vertices[face.a])
108
+ b = prepare(@vertices[face.b])
109
+ c = prepare(@vertices[face.c])
110
+ v = []
111
+
112
+ # Construct all of the vertices for this subdivision.
113
+ for i in 0..cols do
114
+ v[i] = []
115
+
116
+ aj = prepare(a.clone.lerp(c, i.to_f / cols.to_f))
117
+ bj = prepare(b.clone.lerp(c, i.to_f / cols.to_f))
118
+ rows = cols - i
119
+
120
+ for j in 0..rows do
121
+ v[i][j] = if j.zero? && i == cols
122
+ aj
123
+ else
124
+ prepare(aj.clone.lerp(bj, j.to_f / rows.to_f))
125
+ end
126
+ end
127
+ end
128
+
129
+ # Construct all of the faces
130
+ for i in 0...cols do
131
+ for j in (0...(2 * (cols - i) - 1)) do
132
+ k = j/2
133
+
134
+ if j.even?
135
+ make(
136
+ v[i][k + 1],
137
+ v[i + 1][k],
138
+ v[i][k]
139
+ )
140
+ else
141
+ make(
142
+ v[i][k + 1],
143
+ v[i + 1][k + 1],
144
+ v[i + 1][k]
145
+ )
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ # Angle around the Y axis, counter-clockwise when looking from above.
152
+ def azimuth(vector)
153
+ Math.atan2(vector.z, -vector.x)
154
+ end
155
+
156
+ # Angle above the XZ plane.
157
+ def inclination(vector)
158
+ Math.atan2(-vector.y, Math.sqrt(vector.x * vector.x + vector.z * vector.z))
159
+ end
160
+
161
+ # Texture fixing helper. Spheres have some odd behaviours.
162
+ def correct_uv(uv, vector, azimuth)
163
+ return Vector2.new(uv.x - 1.0, uv.y) if azimuth < 0
164
+ return Vector2.new(azimuth / 2.0 / Math::PI + 0.5, uv.y) if vector.x.zero? && vector.z.zero?
165
+ uv.clone
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,80 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+
4
+ module Mittsu
5
+ class RingGeometry < Geometry
6
+ def initialize(inner_radius = 0.0, outer_radius = 50.0, theta_segments = 8, phi_segments = 8, theta_start = 0.0, theta_length = (Math::PI * 2.0))
7
+ super()
8
+
9
+ @type = 'RingGeometry'
10
+
11
+ @parameters = {
12
+ inner_radius: inner_radius,
13
+ outer_radius: outer_radius,
14
+ theta_segments: theta_segments,
15
+ phi_segments: phi_segments,
16
+ theta_start: theta_start,
17
+ theta_length: theta_length
18
+ }
19
+
20
+ theta_segments = [3, theta_segments].max
21
+ phi_segments = [1, phi_segments].max
22
+
23
+ uvs = []
24
+ radius = inner_radius
25
+ radius_step = ((outer_radius - inner_radius) / phi_segments.to_f)
26
+
27
+ for i in 0..phi_segments do # concentric circles inside ring
28
+ for o in 0..theta_segments do # number of segments per circle
29
+ vertex = Vector3.new
30
+ segment = theta_start + o.to_f / theta_segments.to_f * theta_length
31
+ vertex.x = radius * Math.cos(segment)
32
+ vertex.y = radius * Math.sin(segment)
33
+
34
+ @vertices << vertex
35
+ uvs << Vector2.new((vertex.x / outer_radius + 1.0) / 2.0, (vertex.y / outer_radius + 1.0) / 2.0)
36
+ end
37
+
38
+ radius += radius_step
39
+ end
40
+
41
+ n = Vector3.new(0.0, 0.0, 1.0)
42
+
43
+ for i in 0...phi_segments do # concentric circles inside ring
44
+ theta_segment = i * (theta_segments + 1)
45
+
46
+ for o in 0...theta_segments do # number of segments per circle
47
+ segment = o + theta_segment
48
+
49
+ v1 = segment
50
+ v2 = segment + theta_segments + 1
51
+ v3 = segment + theta_segments + 2
52
+
53
+ @faces << Face3.new(v1, v2, v3, [n.clone, n.clone, n.clone])
54
+ @face_vertex_uvs[0] << [uvs[v1].clone, uvs[v2].clone, uvs[v3].clone]
55
+
56
+ v1 = segment
57
+ v2 = segment + theta_segments + 2
58
+ v3 = segment + 1
59
+
60
+ @faces << Face3.new(v1, v2, v3, [n.clone, n.clone, n.clone])
61
+ @face_vertex_uvs[0] << [uvs[v1].clone, uvs[v2].clone, uvs[v3].clone]
62
+ end
63
+ end
64
+
65
+ compute_face_normals
66
+ @bounding_sphere = Sphere.new(Vector3.new, radius)
67
+ end
68
+
69
+ def clone
70
+ RingGeometry.new(
71
+ @parameters[:inner_radius],
72
+ @parameters[:outer_radius],
73
+ @parameters[:theta_segments],
74
+ @parameters[:phi_segments],
75
+ @parameters[:theta_start],
76
+ @parameters[:theta_length]
77
+ )
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,26 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+ require 'mittsu/extras/geometries/polyhedron_geometry'
4
+
5
+ module Mittsu
6
+ class TetrahedronGeometry < PolyhedronGeometry
7
+ def initialize(radius = 1.0, detail = 0)
8
+ vertices = [
9
+ 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1
10
+ ]
11
+
12
+ indices = [
13
+ 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
14
+ ]
15
+
16
+ super(vertices, indices, radius, detail)
17
+
18
+ @type = 'TetrahedronGeometry'
19
+
20
+ @parameters = {
21
+ radius: radius,
22
+ detail: detail
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,63 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+
4
+ module Mittsu
5
+ class TorusGeometry < Geometry
6
+ def initialize(radius = 100.0, tube = 40.0, radial_segments = 8, tubular_segments = 6, arc = (Math::PI * 2.0))
7
+ super()
8
+
9
+ @type = 'TorusGeometry'
10
+
11
+ @parameters = {
12
+ radius: radius,
13
+ tube: tube,
14
+ radial_segments: radial_segments,
15
+ tubular_segments: tubular_segments,
16
+ arc: arc
17
+ }
18
+
19
+ center = Vector3.new
20
+ uvs = []
21
+ normals = []
22
+
23
+ for j in 0..radial_segments do
24
+ for i in 0..tubular_segments do
25
+ u = i.to_f / tubular_segments * arc
26
+ v = j.to_f / radial_segments * Math::PI * 2.0
27
+
28
+ center.x = radius * Math.cos(u)
29
+ center.y = radius * Math.sin(u)
30
+
31
+ vertex = Vector3.new
32
+ vertex.x = (radius + tube * Math.cos(v)) * Math.cos(u)
33
+ vertex.y = (radius + tube * Math.cos(v)) * Math.sin(u)
34
+ vertex.z = tube * Math.sin(v)
35
+
36
+ @vertices << vertex
37
+
38
+ uvs << Vector2.new(i.to_f / tubular_segments, j.to_f / radial_segments)
39
+ normals << vertex.clone.sub(center).normalize
40
+ end
41
+ end
42
+
43
+ for j in 1..radial_segments do
44
+ for i in 1..tubular_segments do
45
+ a = (tubular_segments + 1) * j + i - 1
46
+ b = (tubular_segments + 1) * (j - 1) + i - 1
47
+ c = (tubular_segments + 1) * (j - 1) + i
48
+ d = (tubular_segments + 1) * j + i
49
+
50
+ face = Face3.new(a, b, d, [normals[a].clone, normals[b].clone, normals[d].clone])
51
+ @faces << face
52
+ @face_vertex_uvs[0] << [uvs[a].clone, uvs[b].clone, uvs[d].clone]
53
+
54
+ face = Face3.new(b, c, d, [normals[b].clone, normals[c].clone, normals[d].clone])
55
+ @faces << face
56
+ @face_vertex_uvs[0] << [uvs[b].clone, uvs[c].clone, uvs[d].clone]
57
+ end
58
+ end
59
+
60
+ compute_face_normals
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,120 @@
1
+ module Mittsu
2
+ class TorusKnotBufferGeometry < BufferGeometry
3
+ def initialize(radius = 100.0, tube = 40.0, radial_segments = 64, tubular_segments = 8, p_val = 2, q_val = 3)
4
+ super()
5
+
6
+ @type = 'TorusKnotBufferGeometry'
7
+
8
+ @parameters = {
9
+ radius: radius,
10
+ tube: tube,
11
+ radial_segments: radial_segments,
12
+ tubular_segments: tubular_segments,
13
+ p_val: p_val,
14
+ q_val: q_val
15
+ }
16
+
17
+ # buffers
18
+
19
+ indices = []
20
+ vertices = []
21
+ normals = []
22
+ uvs = []
23
+
24
+ # helper variables
25
+
26
+ vertex = Vector3.new
27
+ normal = Vector3.new
28
+
29
+ p1 = Vector3.new
30
+ p2 = Vector3.new
31
+
32
+ b = Vector3.new
33
+ t = Vector3.new
34
+ n = Vector3.new
35
+
36
+ # generate vertices, normals and uvs
37
+
38
+ for i in 0..tubular_segments do
39
+ # the radian "u" is used to calculate the position on the torus curve of the current tubular segement
40
+ u = i.to_f / tubular_segments.to_f * p_val.to_f * Math::PI * 2.0
41
+
42
+ # now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
43
+ # these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
44
+ calculate_position_on_curve(u, p_val, q_val, radius, p1)
45
+ calculate_position_on_curve(u + 0.01, p_val, q_val, radius, p2)
46
+
47
+ # calculate orthonormal basis
48
+ t.sub_vectors(p2, p1)
49
+ n.add_vectors(p2, p1)
50
+ b.cross_vectors(t, n)
51
+ n.cross_vectors(b, t)
52
+
53
+ # normalize B, N. T can be ignored, we don't use it
54
+ b.normalize
55
+ n.normalize
56
+
57
+ for j in 0..radial_segments do
58
+ # now calculate the vertices. they are nothing more than an extrusion of the torus curve.
59
+ # because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
60
+ v = j.to_f / radial_segments.to_f * Math::PI * 2.0
61
+ cx = -tube * Math.cos(v)
62
+ cy = tube * Math.sin(v)
63
+
64
+ # now calculate the final vertex position.
65
+ # first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
66
+ vertex.x = p1.x + (cx * n.x + cy * b.x)
67
+ vertex.y = p1.y + (cx * n.y + cy * b.y)
68
+ vertex.z = p1.z + (cx * n.z + cy * b.z)
69
+
70
+ vertices += vertex.elements
71
+
72
+ # normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
73
+ normal.sub_vectors(vertex, p1).normalize
74
+
75
+ normals += normal.elements
76
+
77
+ # uv
78
+ uvs << i.to_f / tubular_segments.to_f
79
+ uvs << j.to_f / radial_segments.to_f
80
+ end
81
+ end
82
+
83
+ # generate indices
84
+
85
+ for j in 1..tubular_segments do
86
+ for i in 1..radial_segments do
87
+ # indices
88
+ a = (radial_segments + 1) * (j - 1) + (i - 1)
89
+ b = (radial_segments + 1) * j + (i - 1)
90
+ c = (radial_segments + 1) * j + i
91
+ d = (radial_segments + 1) * (j - 1) + i
92
+
93
+ # faces
94
+ indices += [a, b, d]
95
+ indices += [b, c, d]
96
+ end
97
+ end
98
+
99
+ # build geometry
100
+
101
+ self[:index] = BufferAttribute.new(indices, 1)
102
+ self[:position] = BufferAttribute.new(vertices, 3)
103
+ self[:normal] = BufferAttribute.new(normals, 3)
104
+ self[:uv] = BufferAttribute.new(uvs, 2)
105
+ end
106
+
107
+ private
108
+
109
+ def calculate_position_on_curve(u, p_val, q_val, radius, position)
110
+ cu = Math.cos(u)
111
+ su = Math.sin(u)
112
+ qu_over_p = q_val.to_f / p_val.to_f * u
113
+ cs = Math.cos(qu_over_p)
114
+
115
+ position.x = radius * (2.0 + cs) * 0.5 * cu
116
+ position.y = radius * (2.0 + cs) * su * 0.5
117
+ position.z = radius * Math.sin(qu_over_p) * 0.5
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,25 @@
1
+ require 'mittsu/core'
2
+ require 'mittsu/math'
3
+ require 'mittsu/extras/geometries/torus_knot_buffer_geometry'
4
+
5
+ module Mittsu
6
+ class TorusKnotGeometry < Geometry
7
+ def initialize(radius = 100.0, tube = 40.0, radial_segments = 64, tubular_segments = 8, p_val = 2, q_val = 3)
8
+ super()
9
+
10
+ @type = 'TorusKnotGeometry'
11
+
12
+ @parameters = {
13
+ radius: radius,
14
+ tube: tube,
15
+ radial_segments: radial_segments,
16
+ tubular_segments: tubular_segments,
17
+ p_val: p_val,
18
+ q_val: q_val
19
+ }
20
+
21
+ from_buffer_geometry(TorusKnotBufferGeometry.new(radius, tube, tubular_segments, radial_segments, p_val, q_val))
22
+ merge_vertices
23
+ end
24
+ end
25
+ end
@@ -1,6 +1,6 @@
1
1
  module Mittsu
2
2
  class Vector
3
- attr_accessor :elements
3
+ attr_accessor :elements, :uv, :index
4
4
 
5
5
  def initialize(elements)
6
6
  @elements = elements
@@ -1,4 +1,4 @@
1
1
  module Mittsu
2
- VERSION = "0.2.4"
2
+ VERSION = "0.3.0"
3
3
  REVISION = "71"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mittsu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-16 00:00:00.000000000 Z
11
+ date: 2018-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opengl-bindings
@@ -181,7 +181,23 @@ files:
181
181
  - lib/mittsu/extras.rb
182
182
  - lib/mittsu/extras/geometries.rb
183
183
  - lib/mittsu/extras/geometries/box_geometry.rb
184
+ - lib/mittsu/extras/geometries/circle_geometry.rb
185
+ - lib/mittsu/extras/geometries/cylinder_geometry.rb
186
+ - lib/mittsu/extras/geometries/dodecahedron_geometry.rb
187
+ - lib/mittsu/extras/geometries/icosahedron_geometry.rb
188
+ - lib/mittsu/extras/geometries/lathe_geometry.rb
189
+ - lib/mittsu/extras/geometries/octahedron_geometry.rb
190
+ - lib/mittsu/extras/geometries/parametric_buffer_geometry.rb
191
+ - lib/mittsu/extras/geometries/parametric_geometry.rb
192
+ - lib/mittsu/extras/geometries/plane_buffer_geometry.rb
193
+ - lib/mittsu/extras/geometries/plane_geometry.rb
194
+ - lib/mittsu/extras/geometries/polyhedron_geometry.rb
195
+ - lib/mittsu/extras/geometries/ring_geometry.rb
184
196
  - lib/mittsu/extras/geometries/sphere_geometry.rb
197
+ - lib/mittsu/extras/geometries/tetrahedron_geometry.rb
198
+ - lib/mittsu/extras/geometries/torus_geometry.rb
199
+ - lib/mittsu/extras/geometries/torus_knot_buffer_geometry.rb
200
+ - lib/mittsu/extras/geometries/torus_knot_geometry.rb
185
201
  - lib/mittsu/extras/helpers.rb
186
202
  - lib/mittsu/extras/helpers/camera_helper.rb
187
203
  - lib/mittsu/extras/image.rb