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 +4 -4
- data/lib/mittsu/core/geometry.rb +9 -6
- data/lib/mittsu/extras/geometries.rb +13 -0
- data/lib/mittsu/extras/geometries/circle_geometry.rb +48 -0
- data/lib/mittsu/extras/geometries/cylinder_geometry.rb +145 -0
- data/lib/mittsu/extras/geometries/dodecahedron_geometry.rb +56 -0
- data/lib/mittsu/extras/geometries/icosahedron_geometry.rb +33 -0
- data/lib/mittsu/extras/geometries/lathe_geometry.rb +78 -0
- data/lib/mittsu/extras/geometries/octahedron_geometry.rb +26 -0
- data/lib/mittsu/extras/geometries/parametric_buffer_geometry.rb +92 -0
- data/lib/mittsu/extras/geometries/parametric_geometry.rb +93 -0
- data/lib/mittsu/extras/geometries/plane_buffer_geometry.rb +81 -0
- data/lib/mittsu/extras/geometries/plane_geometry.rb +22 -0
- data/lib/mittsu/extras/geometries/polyhedron_geometry.rb +168 -0
- data/lib/mittsu/extras/geometries/ring_geometry.rb +80 -0
- data/lib/mittsu/extras/geometries/tetrahedron_geometry.rb +26 -0
- data/lib/mittsu/extras/geometries/torus_geometry.rb +63 -0
- data/lib/mittsu/extras/geometries/torus_knot_buffer_geometry.rb +120 -0
- data/lib/mittsu/extras/geometries/torus_knot_geometry.rb +25 -0
- data/lib/mittsu/math/vector.rb +1 -1
- data/lib/mittsu/version.rb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d75b0ef6c6615fff22f50ab9f3bc438e5c2631d5924f30da913df6403d5ccd0
|
4
|
+
data.tar.gz: 4656d50526e5be69dd19f3f0de87b4f93de5ad0a2e664b6277b023b885d7c3a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4093db783cef7214c92fa5ce723cf84466a4dcd30d1e7a8fe6c5b9ff41f4be13d04eaeb072e30e6e039191d410303adf47c55288429439412e746ba300e05918
|
7
|
+
data.tar.gz: e3bafbb95cff8e606f36e6e456314a75cbfc9c0284022ef73258d40316918fd87dce5b11b21aa1b25802a071b91b413df53de8220f1294eadf892600f79868fd
|
data/lib/mittsu/core/geometry.rb
CHANGED
@@ -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.
|
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
|
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.
|
136
|
+
if geometry.bounding_box
|
134
137
|
@bounding_box = geometry.bounding_box.clone
|
135
138
|
end
|
136
|
-
if geometry.
|
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(
|
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
|
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
|
data/lib/mittsu/math/vector.rb
CHANGED
data/lib/mittsu/version.rb
CHANGED
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.
|
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-
|
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
|