mittsu 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.
Files changed (203) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +3 -0
  4. data/CODE_OF_CONDUCT.md +13 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +39 -0
  8. data/Rakefile +7 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/examples/01_-_Default1noCulling.png +0 -0
  12. data/examples/01_scene_example.rb +14 -0
  13. data/examples/02_box_mesh_example.rb +30 -0
  14. data/examples/02_sphere_mesh_example.rb +30 -0
  15. data/examples/03_complex_object_example.rb +52 -0
  16. data/examples/04_ambient_light_example.rb +33 -0
  17. data/examples/04_dir_light_example.rb +36 -0
  18. data/examples/04_hemi_light_example.rb +30 -0
  19. data/examples/04_point_light_example.rb +50 -0
  20. data/examples/04_spot_light_example.rb +44 -0
  21. data/examples/05_earth_example.rb +42 -0
  22. data/examples/05_earth_moon_example.rb +46 -0
  23. data/examples/05_texture_example.rb +32 -0
  24. data/examples/06_cube_texture_example.rb +36 -0
  25. data/examples/06_skybox_example.rb +60 -0
  26. data/examples/07_earth_normal_example.rb +36 -0
  27. data/examples/08_shadow_example.rb +87 -0
  28. data/examples/09_line_example.rb +52 -0
  29. data/examples/10_obj_loader_example.rb +68 -0
  30. data/examples/11_character_input_example.rb +18 -0
  31. data/examples/11_continuous_keyboard_input_example.rb +35 -0
  32. data/examples/11_keyboard_input_example.rb +43 -0
  33. data/examples/12_mouse_click_example.rb +38 -0
  34. data/examples/12_mouse_motion_example.rb +35 -0
  35. data/examples/12_mouse_scroll_example.rb +36 -0
  36. data/examples/12_orbit_zoom_example.rb +68 -0
  37. data/examples/13_joystick_example.rb +80 -0
  38. data/examples/cubemap/tron_bk.png +0 -0
  39. data/examples/cubemap/tron_dn.png +0 -0
  40. data/examples/cubemap/tron_ft.png +0 -0
  41. data/examples/cubemap/tron_lf.png +0 -0
  42. data/examples/cubemap/tron_rt.png +0 -0
  43. data/examples/cubemap/tron_up.png +0 -0
  44. data/examples/earth.png +0 -0
  45. data/examples/earth_normal.png +0 -0
  46. data/examples/example_helper.rb +2 -0
  47. data/examples/male-02-1noCulling.png +0 -0
  48. data/examples/male02.mtl +54 -0
  49. data/examples/male02.obj +13888 -0
  50. data/examples/moon.png +0 -0
  51. data/examples/orig_02_-_Defaul1noCulling.png +0 -0
  52. data/examples/texture.png +0 -0
  53. data/lib/mittsu.rb +15 -0
  54. data/lib/mittsu/cameras.rb +4 -0
  55. data/lib/mittsu/cameras/camera.rb +34 -0
  56. data/lib/mittsu/cameras/cube_camera.rb +74 -0
  57. data/lib/mittsu/cameras/orthographic_camera.rb +53 -0
  58. data/lib/mittsu/cameras/perspective_camera.rb +115 -0
  59. data/lib/mittsu/constants.rb +160 -0
  60. data/lib/mittsu/core.rb +10 -0
  61. data/lib/mittsu/core/buffer_attribute.rb +87 -0
  62. data/lib/mittsu/core/buffer_geometry.rb +694 -0
  63. data/lib/mittsu/core/clock.rb +44 -0
  64. data/lib/mittsu/core/dynamic_buffer_attribute.rb +16 -0
  65. data/lib/mittsu/core/event_dispatcher.rb +39 -0
  66. data/lib/mittsu/core/face3.rb +30 -0
  67. data/lib/mittsu/core/geometry.rb +596 -0
  68. data/lib/mittsu/core/hash_array.rb +36 -0
  69. data/lib/mittsu/core/hash_object.rb +19 -0
  70. data/lib/mittsu/core/object_3d.rb +421 -0
  71. data/lib/mittsu/core/raycaster.rb +78 -0
  72. data/lib/mittsu/extras.rb +3 -0
  73. data/lib/mittsu/extras/geometries.rb +2 -0
  74. data/lib/mittsu/extras/geometries/box_geometry.rb +108 -0
  75. data/lib/mittsu/extras/geometries/sphere_geometry.rb +88 -0
  76. data/lib/mittsu/extras/helpers.rb +1 -0
  77. data/lib/mittsu/extras/helpers/camera_helper.rb +155 -0
  78. data/lib/mittsu/extras/image.rb +3 -0
  79. data/lib/mittsu/extras/image_utils.rb +80 -0
  80. data/lib/mittsu/lights.rb +7 -0
  81. data/lib/mittsu/lights/ambient_light.rb +16 -0
  82. data/lib/mittsu/lights/area_light.rb +24 -0
  83. data/lib/mittsu/lights/directional_light.rb +131 -0
  84. data/lib/mittsu/lights/hemisphere_light.rb +29 -0
  85. data/lib/mittsu/lights/light.rb +21 -0
  86. data/lib/mittsu/lights/point_light.rb +27 -0
  87. data/lib/mittsu/lights/spot_light.rb +104 -0
  88. data/lib/mittsu/loaders.rb +7 -0
  89. data/lib/mittsu/loaders/cache.rb +53 -0
  90. data/lib/mittsu/loaders/file_loader.rb +22 -0
  91. data/lib/mittsu/loaders/image_loader.rb +32 -0
  92. data/lib/mittsu/loaders/loader.rb +212 -0
  93. data/lib/mittsu/loaders/loading_manager.rb +17 -0
  94. data/lib/mittsu/loaders/mtl_loader.rb +242 -0
  95. data/lib/mittsu/loaders/obj_mtl_loader.rb +225 -0
  96. data/lib/mittsu/materials.rb +7 -0
  97. data/lib/mittsu/materials/line_basic_material.rb +39 -0
  98. data/lib/mittsu/materials/material.rb +156 -0
  99. data/lib/mittsu/materials/mesh_basic_material.rb +122 -0
  100. data/lib/mittsu/materials/mesh_face_material.rb +30 -0
  101. data/lib/mittsu/materials/mesh_lambert_material.rb +126 -0
  102. data/lib/mittsu/materials/mesh_phong_material.rb +152 -0
  103. data/lib/mittsu/materials/shader_material.rb +108 -0
  104. data/lib/mittsu/math.rb +105 -0
  105. data/lib/mittsu/math/box2.rb +135 -0
  106. data/lib/mittsu/math/box3.rb +194 -0
  107. data/lib/mittsu/math/color.rb +252 -0
  108. data/lib/mittsu/math/color_keywords.rb +151 -0
  109. data/lib/mittsu/math/euler.rb +182 -0
  110. data/lib/mittsu/math/frustum.rb +106 -0
  111. data/lib/mittsu/math/line3.rb +76 -0
  112. data/lib/mittsu/math/matrix3.rb +163 -0
  113. data/lib/mittsu/math/matrix4.rb +581 -0
  114. data/lib/mittsu/math/plane.rb +128 -0
  115. data/lib/mittsu/math/quaternion.rb +309 -0
  116. data/lib/mittsu/math/ray.rb +292 -0
  117. data/lib/mittsu/math/sphere.rb +91 -0
  118. data/lib/mittsu/math/spline.rb +128 -0
  119. data/lib/mittsu/math/triangle.rb +121 -0
  120. data/lib/mittsu/math/vector2.rb +238 -0
  121. data/lib/mittsu/math/vector3.rb +491 -0
  122. data/lib/mittsu/math/vector4.rb +414 -0
  123. data/lib/mittsu/objects.rb +3 -0
  124. data/lib/mittsu/objects/group.rb +8 -0
  125. data/lib/mittsu/objects/line.rb +143 -0
  126. data/lib/mittsu/objects/mesh.rb +243 -0
  127. data/lib/mittsu/renderers.rb +1 -0
  128. data/lib/mittsu/renderers/glfw_window.rb +216 -0
  129. data/lib/mittsu/renderers/opengl/opengl_debug.rb +38 -0
  130. data/lib/mittsu/renderers/opengl/opengl_program.rb +402 -0
  131. data/lib/mittsu/renderers/opengl/opengl_shader.rb +58 -0
  132. data/lib/mittsu/renderers/opengl/opengl_state.rb +207 -0
  133. data/lib/mittsu/renderers/opengl/plugins/shadow_map_plugin.rb +416 -0
  134. data/lib/mittsu/renderers/opengl_render_target.rb +87 -0
  135. data/lib/mittsu/renderers/opengl_renderer.rb +3376 -0
  136. data/lib/mittsu/renderers/shaders/shader_chunk.rb +12 -0
  137. data/lib/mittsu/renderers/shaders/shader_chunk/alphamap_fragment.glsl +5 -0
  138. data/lib/mittsu/renderers/shaders/shader_chunk/alphamap_pars_fragment.glsl +5 -0
  139. data/lib/mittsu/renderers/shaders/shader_chunk/alphatest_fragment.glsl +5 -0
  140. data/lib/mittsu/renderers/shaders/shader_chunk/bumpmap_pars_fragment.glsl +40 -0
  141. data/lib/mittsu/renderers/shaders/shader_chunk/color_fragment.glsl +5 -0
  142. data/lib/mittsu/renderers/shaders/shader_chunk/color_pars_fragment.glsl +5 -0
  143. data/lib/mittsu/renderers/shaders/shader_chunk/color_pars_vertex.glsl +5 -0
  144. data/lib/mittsu/renderers/shaders/shader_chunk/color_vertex.glsl +5 -0
  145. data/lib/mittsu/renderers/shaders/shader_chunk/common.glsl +60 -0
  146. data/lib/mittsu/renderers/shaders/shader_chunk/default_vertex.glsl +15 -0
  147. data/lib/mittsu/renderers/shaders/shader_chunk/defaultnormal_vertex.glsl +21 -0
  148. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_fragment.glsl +62 -0
  149. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_pars_fragment.glsl +21 -0
  150. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_pars_vertex.glsl +7 -0
  151. data/lib/mittsu/renderers/shaders/shader_chunk/envmap_vertex.glsl +17 -0
  152. data/lib/mittsu/renderers/shaders/shader_chunk/fog_fragment.glsl +26 -0
  153. data/lib/mittsu/renderers/shaders/shader_chunk/fog_pars_fragment.glsl +15 -0
  154. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_fragment.glsl +5 -0
  155. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_pars_fragment.glsl +6 -0
  156. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_pars_vertex.glsl +5 -0
  157. data/lib/mittsu/renderers/shaders/shader_chunk/lightmap_vertex.glsl +5 -0
  158. data/lib/mittsu/renderers/shaders/shader_chunk/lights_lambert_pars_vertex.glsl +43 -0
  159. data/lib/mittsu/renderers/shaders/shader_chunk/lights_lambert_vertex.glsl +196 -0
  160. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_fragment.glsl +243 -0
  161. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_pars_fragment.glsl +58 -0
  162. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_pars_vertex.glsl +5 -0
  163. data/lib/mittsu/renderers/shaders/shader_chunk/lights_phong_vertex.glsl +5 -0
  164. data/lib/mittsu/renderers/shaders/shader_chunk/linear_to_gamma_fragment.glsl +2 -0
  165. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_fragment.glsl +5 -0
  166. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_pars_fragment.glsl +12 -0
  167. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_pars_vertex.glsl +11 -0
  168. data/lib/mittsu/renderers/shaders/shader_chunk/logdepthbuf_vertex.glsl +15 -0
  169. data/lib/mittsu/renderers/shaders/shader_chunk/map_fragment.glsl +9 -0
  170. data/lib/mittsu/renderers/shaders/shader_chunk/map_pars_fragment.glsl +11 -0
  171. data/lib/mittsu/renderers/shaders/shader_chunk/map_pars_vertex.glsl +6 -0
  172. data/lib/mittsu/renderers/shaders/shader_chunk/map_particle_fragment.glsl +5 -0
  173. data/lib/mittsu/renderers/shaders/shader_chunk/map_particle_pars_fragment.glsl +6 -0
  174. data/lib/mittsu/renderers/shaders/shader_chunk/map_vertex.glsl +5 -0
  175. data/lib/mittsu/renderers/shaders/shader_chunk/morphnormal_vertex.glsl +12 -0
  176. data/lib/mittsu/renderers/shaders/shader_chunk/morphtarget_pars_vertex.glsl +13 -0
  177. data/lib/mittsu/renderers/shaders/shader_chunk/morphtarget_vertex.glsl +20 -0
  178. data/lib/mittsu/renderers/shaders/shader_chunk/normalmap_pars_fragment.glsl +27 -0
  179. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_fragment.glsl +217 -0
  180. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_pars_fragment.glsl +19 -0
  181. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_pars_vertex.glsl +6 -0
  182. data/lib/mittsu/renderers/shaders/shader_chunk/shadowmap_vertex.glsl +9 -0
  183. data/lib/mittsu/renderers/shaders/shader_chunk/skinbase_vertex.glsl +8 -0
  184. data/lib/mittsu/renderers/shaders/shader_chunk/skinning_pars_vertex.glsl +47 -0
  185. data/lib/mittsu/renderers/shaders/shader_chunk/skinning_vertex.glsl +20 -0
  186. data/lib/mittsu/renderers/shaders/shader_chunk/skinnormal_vertex.glsl +20 -0
  187. data/lib/mittsu/renderers/shaders/shader_chunk/specularmap_fragment.glsl +12 -0
  188. data/lib/mittsu/renderers/shaders/shader_chunk/specularmap_pars_fragment.glsl +5 -0
  189. data/lib/mittsu/renderers/shaders/shader_chunk/worldpos_vertex.glsl +17 -0
  190. data/lib/mittsu/renderers/shaders/shader_lib.rb +420 -0
  191. data/lib/mittsu/renderers/shaders/uniforms_lib.rb +107 -0
  192. data/lib/mittsu/renderers/shaders/uniforms_utils.rb +31 -0
  193. data/lib/mittsu/scenes.rb +1 -0
  194. data/lib/mittsu/scenes/scene.rb +27 -0
  195. data/lib/mittsu/textures.rb +5 -0
  196. data/lib/mittsu/textures/compressed_texture.rb +30 -0
  197. data/lib/mittsu/textures/cube_texture.rb +19 -0
  198. data/lib/mittsu/textures/data_texture.rb +17 -0
  199. data/lib/mittsu/textures/texture.rb +92 -0
  200. data/lib/mittsu/textures/video_texture.rb +17 -0
  201. data/lib/mittsu/version.rb +4 -0
  202. data/mittsu.gemspec +31 -0
  203. metadata +357 -0
@@ -0,0 +1,10 @@
1
+ require "mittsu/core/buffer_attribute"
2
+ require "mittsu/core/buffer_geometry"
3
+ require "mittsu/core/clock"
4
+ require "mittsu/core/dynamic_buffer_attribute"
5
+ require "mittsu/core/event_dispatcher"
6
+ require "mittsu/core/face3"
7
+ require "mittsu/core/geometry"
8
+ require "mittsu/core/object_3d"
9
+ require "mittsu/core/raycaster"
10
+ require "mittsu/core/hash_array"
@@ -0,0 +1,87 @@
1
+ module Mittsu
2
+ class BufferAttribute
3
+ attr_accessor :array, :item_size, :needs_update
4
+
5
+ def initialize(array, item_size)
6
+ @array = array
7
+ @item_size = item_size
8
+
9
+ @needs_update = false
10
+ end
11
+
12
+ def length
13
+ @array.length
14
+ end
15
+
16
+ def copy_at(index1, attribute, index2)
17
+ index1 *= @item_size
18
+ index2 *= attribute.item_size
19
+
20
+ @item_size.times do |i|
21
+ @array[index1 + i] = attribute.array[index2 + i]
22
+ end
23
+
24
+ self
25
+ end
26
+
27
+ def set(value, offset)
28
+ offset ||= 0
29
+
30
+ @array[offset, value.length] = value
31
+
32
+ self
33
+ end
34
+
35
+ def set_x(index, x)
36
+ @array[index * @item_size] = x
37
+
38
+ self
39
+ end
40
+
41
+ def set_y(index, y)
42
+ @array[index * @item_size + 1] = y
43
+
44
+ self
45
+ end
46
+
47
+ def set_z(index, z)
48
+ @array[index * @item_size + 2] = z
49
+
50
+ self
51
+ end
52
+
53
+ def set_xy(index, x, y)
54
+ index *= @item_size
55
+
56
+ @array[index ] = x
57
+ @array[index + 1] = y
58
+
59
+ self
60
+ end
61
+
62
+ def set_xyz(index, x, y, z)
63
+ index *= @item_size
64
+
65
+ @array[index ] = x
66
+ @array[index + 1] = y
67
+ @array[index + 2] = z
68
+
69
+ self
70
+ end
71
+
72
+ def set_xyzw(index, x, y, z, w)
73
+ index *= @item_size
74
+
75
+ @array[index ] = x
76
+ @array[index + 1] = y
77
+ @array[index + 2] = z
78
+ @array[index + 3] = w
79
+
80
+ self
81
+ end
82
+
83
+ def clone
84
+ BufferAttribute.new(@array.clone, @item_size)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,694 @@
1
+ require 'securerandom'
2
+ require 'mittsu'
3
+ require 'mittsu/core/event_dispatcher'
4
+
5
+ module Mittsu
6
+ class BufferGeometry
7
+ include EventDispatcher
8
+
9
+ DrawCall = Struct.new(:start, :count, :index)
10
+
11
+ attr_reader :id, :name, :type, :uuid, :attributes, :draw_calls, :bounding_box, :bounding_sphere
12
+
13
+ def initialize
14
+ @id = (@@id ||= 1).tap { @@id += 1 }
15
+
16
+ @uuid = SecureRandom.uuid
17
+
18
+ @name = ''
19
+ @type = 'BufferGeometry'
20
+
21
+ @attributes = {}
22
+
23
+ @draw_calls = []
24
+ end
25
+
26
+ def keys
27
+ @attributes.keys
28
+ end
29
+
30
+ def []=(key, value)
31
+ @attributes[key] = value
32
+ end
33
+
34
+ def [](key)
35
+ @attributes[key]
36
+ end
37
+
38
+ def add_draw_call(start, count, index_offset = 0)
39
+ @draw_calls << DrawCall.new(start, count, index_offset)
40
+ end
41
+
42
+ def apply_matrix(matrix)
43
+ position = @attributes[:position]
44
+
45
+ if position
46
+ matrix.apply_to_vector3_array(position.array)
47
+ position.needs_update = true
48
+ end
49
+
50
+ normal = @attributes[:normal]
51
+
52
+ if normal
53
+ normal_matrix = Mittsu::Matrix3.new.normal_matrix(matrix)
54
+
55
+ normal_matrix.apply_to_vector3_array(normal.array)
56
+ normal.needs_update = true
57
+ end
58
+
59
+ if @bounding_box
60
+ self.compute_bounding_box
61
+ end
62
+
63
+ if @bounding_sphere
64
+ self.compute_bounding_sphere
65
+ end
66
+
67
+ nil
68
+ end
69
+
70
+ def center
71
+ self.computer_bounding_box
72
+ @bounding_boc.center.negate.tap do |offset|
73
+ self.apply_matrix(Mittsu::Matrix4.new.set_position(offset))
74
+ end
75
+ end
76
+
77
+ def from_geometry(geometry, settings = {})
78
+ vertices = geometry.vertices
79
+ faces = geometry.faces
80
+ face_vertex_uvs = geometry.face_vertex_uvs
81
+ vertex_colors = settings.fetch(:vertex_colors, Mittsu::NoColors)
82
+ has_face_vertex_uv = face_vertex_uvs[0].length > 0
83
+ has_face_vertex_normals = faces[0].vertex_normals.length == 3
84
+
85
+ positions = Array.new(faces.length * 3 * 3)
86
+ self[:position] = Mittsu::BufferAttribute.new(positions, 3)
87
+
88
+ normals = Array.new(faces.length * 3 * 3)
89
+ self[:normal] = Mittsu::BufferAttribute.new(normals, 3)
90
+
91
+ if vertex_colors != Mittsu::NoColors
92
+ colors = Array.new(faces.length * 3 * 3)
93
+ self[:color] = Mittsu::BufferAttribute.new(colors, 3)
94
+ end
95
+
96
+ if has_face_vertex_uv
97
+ uvs = Array.new(faces.length * 3 * 2)
98
+ self[:uv] = Mittsu::BufferAttribute.new(uvs, 2)
99
+ end
100
+
101
+ faces.each_with_index do |face, i|
102
+ i2 = i * 6
103
+ i3 = i * 9
104
+
105
+ set_array3(positions, i3, vertices[face.a], vertices[face.b], vertices[face.b])
106
+
107
+ if has_face_vertex_normals
108
+ set_array3(normals, i3, face.vertex_normals[0], face.vertex_normals[1], face.vertex_normals[2])
109
+ else
110
+ set_array3(normals, i3, face.normal)
111
+ end
112
+
113
+ if vertex_colors == Mittsu::FaceColors
114
+ set_array3(colors, i3, face,color)
115
+ elsif vertex_colors == Mittsu::VertexColors
116
+ set_array3(colors, i3, face.vertex_colors[0], face.vertex_colors[1], face.vertex_colors[2])
117
+ end
118
+
119
+ if has_face_vertex_uv
120
+ set_array2(uvs, i2, face_vertex_uvs[0][i][0], face_vertex_uvs[0][i][1], face_vertex_uvs[0][i][2])
121
+ end
122
+ end
123
+
124
+ self.compute_bounding_sphere
125
+ self
126
+ end
127
+
128
+ def compute_bounding_box
129
+ vector = Mittsu::Vector3.new
130
+
131
+ @bounding_box ||= Mittsu::Box3.new
132
+
133
+ positions = self[:position].array
134
+
135
+ if positions
136
+ @bounding_box.make_empty
137
+
138
+ positions.each_slice(3) do |p|
139
+ vector.set(*p)
140
+ @bounding_box.expand_by_point(vector)
141
+ end
142
+ end
143
+
144
+ if positions.nil? || positions.empty?
145
+ @bounding_box.min.set(0, 0, 0)
146
+ @bounding_box.max.set(0, 0, 0)
147
+ end
148
+
149
+ if @bounding_box.min.x.nan? || @bounding_box.min.y.nan? || @bounding_box.min.z.nan?
150
+ puts 'ERROR: Mittsu::BufferGeometry#compute_bounding_box: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.'
151
+ end
152
+ end
153
+
154
+ def compute_bounding_sphere
155
+ box = Mittsu::Box3.new
156
+ vector = Mittsu::Vector3.new
157
+
158
+ @bounding_sphere ||= Mittsu::Sphere.new
159
+
160
+ positions = self[:position].array
161
+
162
+ if positions
163
+ box.make_empty
164
+ center = @bounding_sphere.center
165
+
166
+ positions.each_slice(3) do |p|
167
+ vector.set(*p)
168
+ box.expand_by_point(vector)
169
+ end
170
+ box.center(center)
171
+
172
+ # hoping to find a boundingSphere with a radius smaller than the
173
+ # boundingSphere of the boundingBox: sqrt(3) smaller in the best case
174
+
175
+ max_radius_sq = 0
176
+
177
+ positions.each_slice(3) do |p|
178
+ vector.set(*p)
179
+ max_radius_sq = [max_radius_sq, center.distance_to_squared(vector)].max
180
+ end
181
+
182
+ @bounding_sphere.radius = Math.sqrt(max_radius_sq)
183
+
184
+ if @bounding_radius.nan?
185
+ puts 'ERROR: Mittsu::BufferGeometry#computeBoundingSphere: Computed radius is NaN. The "position" attribute is likely to have NaN values.'
186
+ end
187
+ end
188
+ end
189
+
190
+ def compute_vertex_normals
191
+ if self[:position]
192
+ positions = self[:position].array
193
+ if self[:normal].nil?
194
+ self[:normal] = Mittsu::BufferAttribute.new(Array.new(positions.length), 3)
195
+ else
196
+ # reset existing normals to zero
197
+ normals = self[:normal].array
198
+ normals.each_index { |i| normals[i] = 0 }
199
+ end
200
+
201
+ normals = self[:normal].array
202
+
203
+ p_a = Mittsu::Vector3.new
204
+ p_b = Mittsu::Vector3.new
205
+ p_c = Mittsu::Vector3.new
206
+
207
+ cb = Mittsu::Vector3.new
208
+ ab = Mittsu::Vector3.new
209
+
210
+ # indexed elements
211
+ if self[:index]
212
+ indices = self[:index].array
213
+
214
+ draw_calls = @draw_calls.length > 0 ? @draw_calls : [DrawCall.new(0, indices.length, 0)]
215
+
216
+ draw_calls.each do |draw_call|
217
+ start = draw_call.start
218
+ count = draw_call.count
219
+ index = draw_call.index
220
+
221
+ i = start
222
+ il = start + count
223
+ while i < il
224
+ v_a = (index + indices[i ]) * 3
225
+ v_b = (index + indices[i + 1]) * 3
226
+ v_c = (index + indices[i + 2]) * 3
227
+
228
+ p_a.from_array(positions, v_a)
229
+ p_b.from_array(positions, v_a)
230
+ p_c.from_array(positions, v_c)
231
+
232
+ cb.sub_vectors(p_c, p_b)
233
+ ab.sub_vectors(p_a, p_b)
234
+ cb.cross(ab)
235
+
236
+ normals[v_a ] += cb.x
237
+ normals[v_a + 1] += cb.y
238
+ normals[v_a + 2] += cb.z
239
+
240
+ normals[v_b ] += cb.x
241
+ normals[v_b + 1] += cb.y
242
+ normals[v_b + 2] += cb.z
243
+
244
+ normals[v_c ] += cb.x
245
+ normals[v_c + 1] += cb.y
246
+ normals[v_c + 2] += cb.z
247
+ i += 3
248
+ end
249
+ end
250
+ else
251
+ # non-indexed elements (unconnected triangle soup)
252
+
253
+ positions.each_slice(9).with_index do |p, i|
254
+ i *= 9
255
+
256
+ p_a.from_array(positions, i)
257
+ p_a.from_array(positions, i + 3)
258
+ p_a.from_array(positions, i + 6)
259
+
260
+ cb.sub_vectors(p_c, p_b)
261
+ ab.sub_vectors(p_a, p_b)
262
+
263
+ set_array3(normals, i, cb)
264
+ end
265
+ end
266
+
267
+ self.normalize_normals
268
+ self[:normal].needs_update = true
269
+ end
270
+ end
271
+
272
+ def compute_tangents
273
+ # based on http://www.terathon.com/code/tangent.html
274
+ # (per vertex tangents)
275
+
276
+ if [:index, :position, :normal, :uv].any { |s| !@attributes.has_key?}
277
+ puts 'WARNING: Mittsu::BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry#computeTangents'
278
+ return
279
+ end
280
+
281
+ indices = self[:index].array
282
+ positions = self[:position].array
283
+ normals = self[:normal].array
284
+ uvs = self[:uv].array
285
+
286
+ n_vertices = position.length / 3
287
+
288
+ if self[:tangent].nil?
289
+ self[:tangent] = Mittsu::BufferAttribute.new(Array.new(4 * n_vertices), 4)
290
+ end
291
+
292
+ tangents = self[:tangent].array
293
+ tan1 = []; tan2 = []
294
+
295
+ n_vertices.times do |k|
296
+ tan1[k] = Mittsu::Vector3.new
297
+ tan2[k] = Mittsu::Vector3.new
298
+ end
299
+
300
+ v_a = Mittsu::Vector3.new
301
+ v_b = Mittsu::Vector3.new
302
+ v_c = Mittsu::Vector3.new
303
+
304
+ uv_a = Mittsu::Vectoe3.new
305
+ uv_b = Mittsu::Vector3.new
306
+ uv_c = Mittsu::Vector3.new
307
+
308
+ sdir = Mittsu::Vector3.new
309
+ tdir = Mittsu::Vector3.new
310
+
311
+ handle_triangle = -> (a, b, c) {
312
+ v_a.from_array(positions, a * 3)
313
+ v_b.from_array(positions, b * 3)
314
+ v_c.from_array(positions, c * 3)
315
+
316
+ uv_a.from_array(uvs, a * 2)
317
+ uv_b.from_array(uvs, b * 2)
318
+ uv_c.from_array(uvs, c * 2)
319
+
320
+ x1 = v_b.x - v_a.x
321
+ x2 = v_c.x - v_a.x
322
+
323
+ y1 = v_b.y - v_a.y
324
+ y2 = v_c.y - v_a.y
325
+
326
+ z1 = v_b.z - v_a.z
327
+ z2 = v_c.z - v_a.z
328
+
329
+ s1 = uv_b.x - uv_a.x
330
+ s2 = uv_c.x - uv_a.x
331
+
332
+ t1 = uv_b.y - uv_a.y
333
+ t2 = uv_c.y - uv_a.y
334
+
335
+ r = 1.0 / (s1 * t2 - s2 * t1)
336
+
337
+ sdir.set(
338
+ (t2 * x1 - t1 * x2) * r,
339
+ (t2 * y1 - t1 * y2) * r,
340
+ (t2 * z1 - t1 * z2) * r
341
+ )
342
+
343
+ tdir.set(
344
+ (s2 * x2 - s2 * x1) * r,
345
+ (s2 * y2 - s2 * y1) * r,
346
+ (s2 * z2 - s2 * z1) * r
347
+ )
348
+
349
+ tan1[a].add(sdir)
350
+ tan1[b].add(sdir)
351
+ tan1[c].add(sdir)
352
+
353
+ tan2[a].add(tdir)
354
+ tan2[b].add(tdir)
355
+ tan2[c].add(tdir)
356
+ }
357
+
358
+ if @draw_calls.empty?
359
+ self.add_draw_call(0, indices.length, 0)
360
+ end
361
+
362
+ @draw_calls.each do |draw_call|
363
+ start = draw_call.start
364
+ count = draw_call.count
365
+ index = draw_call.index
366
+
367
+ i = start
368
+ il = start + count
369
+ while i < il
370
+ i_a = index + indices[i]
371
+ i_b = index + indices[i + 1]
372
+ i_c = index + indices[i + 2]
373
+
374
+ handle_triangle[i_a, i_b, i_c]
375
+ i += 3
376
+ end
377
+ end
378
+
379
+ tmp = Mittsu::Vector3.new
380
+ tmp2 = Mittsu::Vector3.new
381
+ n = Mittsu::Vector3.new
382
+ n2 = Mittsu::Vector3.new
383
+
384
+ handle_vertex = -> (v) {
385
+ n.from_array(normals, v * 3)
386
+ n2.copy(n)
387
+
388
+ t = tan1[v]
389
+
390
+ # Gram-Schmidt orthogonalize
391
+
392
+ tmp.copy(t)
393
+ tmp.sub(n.multiply_scalar(n.dot(t))).normalize
394
+
395
+ # Calculate handedness
396
+
397
+ tmp2.cross_vectors(n2, t)
398
+ test = tmp2.dot(tan2[v])
399
+ w = (test < 0.0) ? -1.0 : 1.0
400
+
401
+ tangents[v * 4 ] = tmp.x
402
+ tangents[v * 4 + 1] = tmp.y
403
+ tangents[v * 4 + 2] = tmp.z
404
+ tangents[v * 4 + 3] = w
405
+ }
406
+
407
+ draw_calls.each do |draw_call|
408
+ start = draw_call.start
409
+ count = draw_call.count
410
+ index = draw_call.index
411
+
412
+ i = start
413
+ il = start + count
414
+ while i < il
415
+ i_a = index + indices[i]
416
+ i_b = index + indices[i + 1]
417
+ i_c = index + indices[i + 2]
418
+
419
+ handle_vertex[i_a]
420
+ handle_vertex[i_b]
421
+ handle_vertex[i_c]
422
+ i += 3
423
+ end
424
+ end
425
+ end
426
+ # Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
427
+ # This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
428
+ # WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
429
+ # size - Defaults to 65535, but allows for larger or smaller chunks.
430
+ def compute_offsets(size = 65535)
431
+ # WebGL limits type of index buffer values to 16-bit.
432
+ # TODO: check what the limit is for OpenGL, as we aren't using WebGL here
433
+
434
+ indices = self[:index].array
435
+ vertices = self[:position].array
436
+
437
+ faces_count = indices.length / 3
438
+
439
+ # puts "Computing buffers in offsets of #{size} -> indices:#{indices.length} vertices:#{vertices.length}"
440
+ # puts "Faces to process: #{(indices.length/3)}"
441
+ # puts "Reordering #{verticesCount} vertices."
442
+
443
+ sorted_indices = Array.new(indices.length) # 16-bit (Uint16Array in THREE.js)
444
+ index_ptr = 0
445
+ vertex_ptr = 0
446
+
447
+ offsets = [DrawCall.new(0, 0, 0)]
448
+ offset = offsets.first
449
+
450
+ duplicated_vertices = 0
451
+ new_vertice_maps = 0
452
+ face_vertices = Array.new(6) # (Int32Array)
453
+ vertex_map = Array.new(vertices.length) # (Int32Array)
454
+ rev_vertex_map = Array.new(vertices.length) # (Int32Array)
455
+ vertices.each_index do |j|
456
+ vertex_map[j] = -1
457
+ rev_vertex_map[j] = -1
458
+ end
459
+
460
+ # Traverse every face and reorder vertices in the proper offsets of 65k.
461
+ # We can have more than 65k entries in the index buffer per offset, but only reference 65k values.
462
+ faces_count.times do |findex|
463
+ new_vertice_maps = 0
464
+
465
+ 3.times do |vo|
466
+ vid = indices[findex * 3 * vo]
467
+ if vertex_map[vid] == -1
468
+ # unmapped vertice
469
+ face_vertices[vo * 2] = vid
470
+ face_vertices[vo * 2 + 1] = -1
471
+ new_vertice_maps += 1
472
+ elsif vertex_map[vid] < offset.index
473
+ # reused vertices from previous block (duplicate)
474
+ face_vertices[vo * 2] = vid
475
+ face_vertices[vo * 2 + 1] = -1
476
+ duplicated_vertices += 1
477
+ else
478
+ # reused vertice in the current block
479
+ face_vertices[vo * 2] =vid
480
+ face_vertices[vo * 2 + 1] = vertec_map[vid]
481
+ end
482
+ end
483
+
484
+ face_max = vertex_ptr + new_vertex_maps
485
+ if face_max > offset.index + size
486
+ new_offset = DrawCall.new(index_ptr, 0, vertex_ptr)
487
+ offsets << new_offset
488
+ offset = new_offset
489
+
490
+ # Re-evaluate reused vertices in light of new offset.
491
+ (0...6).step(2) do |v|
492
+ new_vid = face_vertices[v + 1]
493
+ if (new_vid > -1 && new_vid < offset.index)
494
+ faceVertices[v + 1] = -1
495
+ end
496
+ end
497
+
498
+ # Reindex the face.
499
+ (0...6).step(2) do |v|
500
+ vid = face_vertices[v]
501
+ new_vid = face_vertices[v + 1]
502
+
503
+ if new_vid == -1
504
+ new_vid = vertex_ptr
505
+ vertex_ptr += 1
506
+ end
507
+
508
+ vertex_map[vid] = new_vid
509
+ rev_vertex_map[new_vid] = vid
510
+ sorted_indices [index_ptr] = new_vid - offset.index # XXX: overflows at 16bit
511
+ index_ptr += 1
512
+ offset.count += 1
513
+ end
514
+ end
515
+
516
+ # Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr.
517
+ self.reorder_buffers(sorted_indices, rev_vertex_map, vertex_ptr)
518
+ @draw_calls = offsets
519
+
520
+ # order_time = Time.now
521
+ # puts "Reorder time: #{(order_time - s)}ms"
522
+ # puts "Duplicated #{duplicated_vertices} vertices."
523
+ # puts "Compute Buffers time: #{(Time.now - s)}ms"
524
+ # puts "Draw offsets: #{offsets.length}"
525
+
526
+ offsets
527
+ end
528
+ end
529
+
530
+ def merge(geometry, offset = 0)
531
+ if !geometry.is_a? Mittsu::BufferGeometry
532
+ puts "ERROR: Mittsu::BufferGeometry#merge: geometry not an instance of Mittsu::BufferGeometry. #{geometry.inspect}"
533
+ return
534
+ end
535
+
536
+ @attributes.each_key do |key, attribute1|
537
+ next if attribute1.nil?
538
+
539
+ attribute_array1 = attribute1.array
540
+
541
+ attribute2 = geometry[key]
542
+ attribute_array2 = attribute2.array
543
+
544
+ attribute_size = attribute2.item_size
545
+
546
+ i, j = 0, attribute_size * offset
547
+ while i < attribute_array2.length
548
+ attribute_array1[j] = attribute_array2[i]
549
+ i += 1; j += 1
550
+ end
551
+ end
552
+ self
553
+ end
554
+
555
+ def normalize_normals
556
+ normals = self[:normal].array
557
+
558
+ normals.each_slice(3).with_index do |normal, i|
559
+ x, y, z = *normal
560
+
561
+ n = 1.0 / Math.sqrt(x * x + y * y + z * z)
562
+
563
+ i *= 3
564
+ normals[i] *= n
565
+ normals[i + 1] *= n
566
+ normals[i + 2] *= n
567
+ end
568
+ end
569
+
570
+ # reoderBuffers:
571
+ # Reorder attributes based on a new indexBuffer and indexMap.
572
+ # indexBuffer - Uint16Array of the new ordered indices.
573
+ # indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
574
+ # vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
575
+ def reorder_buffers(index_buffer, index_map, vertex_count)
576
+ # Create a copy of all attributes for reordering
577
+ sorted_attributes = {}
578
+ @attributes.each do |key, attribute|
579
+ next if key == :index
580
+ source_array = attribute.array
581
+ sorted_attributes[key] = source_array.class.new(attribute.item_size * vertex_count)
582
+ end
583
+
584
+ # move attribute positions based on the new index map
585
+ vertex_count.times do |new_vid|
586
+ vid = index_map[new_vid]
587
+ @attributes.each do |key, attribute|
588
+ next if key == :index
589
+ attr_array = attribute.array
590
+ attr_size = attribute.item_size
591
+ sorted_attr = sorted_attributes[key]
592
+ attr_size.times do |k|
593
+ sorted_attr[new_vid * attr_size + k] = attr_array[vid * attr_size + k]
594
+ end
595
+ end
596
+ end
597
+
598
+ # Carry the new sorted buffers locally
599
+ @attributes[:index].array = index_buffer
600
+ @attributes.each do |key, attribute|
601
+ next if key == :index
602
+ attribute.array = sorted_attributes[key]
603
+ attribute.num_items = attribute.item_size * vertex_count
604
+ end
605
+ end
606
+
607
+ def to_json
608
+ output = {
609
+ metadata: {
610
+ version: 4.0,
611
+ type: 'BufferGeometry',
612
+ generator: 'BufferGeometryExporter'
613
+ },
614
+ uuid: @uuid,
615
+ type: @type,
616
+ data: {
617
+ attributes: {}
618
+ }
619
+ }
620
+
621
+ offsets = @draw_calls
622
+
623
+ @attributes.each do |key, attribute|
624
+ array = attribute.array.dup
625
+
626
+ output[:data][:attributes][key] = {
627
+ itemSize: attribute.itemSize,
628
+ type: attribute.array.class.name,
629
+ array: array
630
+ }
631
+ end
632
+
633
+ if !offsets.empty?
634
+ output[:data][:offsets] = offsets.map do |offset|
635
+ { start: offset.start, count: offset.count, index: offet.index}
636
+ end
637
+ end
638
+
639
+ if !bounding_sphere.nil?
640
+ output[:data][:boundingSphere] = {
641
+ center: bounding_sphere.center.to_a,
642
+ radius: bounding_sphere.radius
643
+ }
644
+ end
645
+
646
+ output
647
+ end
648
+
649
+ def clone
650
+ geometry = Mittsu::BufferGeometry.news
651
+
652
+ @attributes.each do |key, attribute|
653
+ geometry[key] = attribute.clone
654
+ end
655
+
656
+ @draw_calls.each do |draw_call|
657
+ geometry.draw_calls << DrawCall.new(draw_call.start, draw_call.count, draw_call.index)
658
+ end
659
+
660
+ geometry
661
+ end
662
+
663
+ def dispose
664
+ self.dispatch_event type: :dispose
665
+ end
666
+
667
+ private
668
+
669
+ def set_array3(array, i3, a, b = a, c = b)
670
+ array[i3 ] = a.x
671
+ array[i3 + 1] = a.y
672
+ array[i3 + 2] = a.z
673
+
674
+ array[i3 + 3] = b.x
675
+ array[i3 + 4] = b.y
676
+ array[i3 + 5] = b.z
677
+
678
+ array[i3 + 6] = c.x
679
+ array[i3 + 7] = c.y
680
+ array[i3 + 8] = c.z
681
+ end
682
+
683
+ def set_array2(array, i2, a, b = a, c = b)
684
+ array[i2 ] = a.x
685
+ array[i2 + 1] = a.y
686
+
687
+ array[i2 + 2] = b.x
688
+ array[i2 + 3] = b.y
689
+
690
+ array[i2 + 4] = c.x
691
+ array[i2 + 5] = c.y
692
+ end
693
+ end
694
+ end