three-rb 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 (145) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +19 -0
  3. data/LICENSE +21 -0
  4. data/README.md +153 -0
  5. data/docs/browser-runtime.md +153 -0
  6. data/docs/implementation-plan.md +874 -0
  7. data/docs/loaded-assets-design.md +400 -0
  8. data/docs/next-work.md +107 -0
  9. data/docs/publishing.md +64 -0
  10. data/docs/release-readiness.md +83 -0
  11. data/examples/browser/README.md +54 -0
  12. data/examples/browser/assets/animated_triangle.gltf +123 -0
  13. data/examples/browser/assets/checker.svg +11 -0
  14. data/examples/browser/assets/compressed_triangle.gltf +74 -0
  15. data/examples/browser/assets/studio.hdr +5 -0
  16. data/examples/browser/assets/triangle.gltf +67 -0
  17. data/examples/browser/composition/README.md +35 -0
  18. data/examples/browser/composition/boot.mjs +6 -0
  19. data/examples/browser/composition/index.html +136 -0
  20. data/examples/browser/composition/main.rb +216 -0
  21. data/examples/browser/composition/smoke_test.mjs +266 -0
  22. data/examples/browser/cube/README.md +41 -0
  23. data/examples/browser/cube/boot.mjs +6 -0
  24. data/examples/browser/cube/index.html +142 -0
  25. data/examples/browser/cube/main.rb +62 -0
  26. data/examples/browser/cube/smoke_test.mjs +99 -0
  27. data/examples/browser/cubemap/README.md +23 -0
  28. data/examples/browser/cubemap/boot.mjs +6 -0
  29. data/examples/browser/cubemap/index.html +142 -0
  30. data/examples/browser/cubemap/main.rb +84 -0
  31. data/examples/browser/cubemap/smoke_test.mjs +91 -0
  32. data/examples/browser/gltf/README.md +23 -0
  33. data/examples/browser/gltf/boot.mjs +6 -0
  34. data/examples/browser/gltf/index.html +142 -0
  35. data/examples/browser/gltf/main.rb +105 -0
  36. data/examples/browser/gltf/smoke_test.mjs +162 -0
  37. data/examples/browser/picking/README.md +33 -0
  38. data/examples/browser/picking/boot.mjs +6 -0
  39. data/examples/browser/picking/index.html +142 -0
  40. data/examples/browser/picking/main.rb +113 -0
  41. data/examples/browser/picking/smoke_test.mjs +78 -0
  42. data/examples/browser/postprocessing/README.md +26 -0
  43. data/examples/browser/postprocessing/boot.mjs +6 -0
  44. data/examples/browser/postprocessing/index.html +142 -0
  45. data/examples/browser/postprocessing/main.rb +117 -0
  46. data/examples/browser/postprocessing/smoke_test.mjs +121 -0
  47. data/examples/browser/primitives/README.md +33 -0
  48. data/examples/browser/primitives/boot.mjs +6 -0
  49. data/examples/browser/primitives/index.html +142 -0
  50. data/examples/browser/primitives/main.rb +116 -0
  51. data/examples/browser/primitives/smoke_test.mjs +113 -0
  52. data/examples/browser/serialization/README.md +33 -0
  53. data/examples/browser/serialization/boot.mjs +6 -0
  54. data/examples/browser/serialization/index.html +142 -0
  55. data/examples/browser/serialization/main.rb +97 -0
  56. data/examples/browser/serialization/smoke_test.mjs +67 -0
  57. data/examples/browser/shared/boot.mjs +79 -0
  58. data/examples/browser/shared/smoke_test_helpers.mjs +151 -0
  59. data/examples/browser/textures/README.md +35 -0
  60. data/examples/browser/textures/boot.mjs +6 -0
  61. data/examples/browser/textures/index.html +142 -0
  62. data/examples/browser/textures/main.rb +142 -0
  63. data/examples/browser/textures/smoke_test.mjs +189 -0
  64. data/lib/three/animation/animation_action.rb +57 -0
  65. data/lib/three/animation/animation_clip.rb +22 -0
  66. data/lib/three/animation/animation_mixer.rb +43 -0
  67. data/lib/three/backends/base.rb +87 -0
  68. data/lib/three/backends/threejs/materialization.rb +143 -0
  69. data/lib/three/backends/threejs/parameters.rb +97 -0
  70. data/lib/three/backends/threejs/resource_management.rb +69 -0
  71. data/lib/three/backends/threejs/ruby_wasm_adapter.rb +873 -0
  72. data/lib/three/backends/threejs/synchronization.rb +224 -0
  73. data/lib/three/backends/threejs.rb +365 -0
  74. data/lib/three/cameras/camera.rb +39 -0
  75. data/lib/three/cameras/orthographic_camera.rb +107 -0
  76. data/lib/three/cameras/perspective_camera.rb +137 -0
  77. data/lib/three/constants.rb +40 -0
  78. data/lib/three/controls/orbit_controls.rb +118 -0
  79. data/lib/three/core/buffer_attribute.rb +151 -0
  80. data/lib/three/core/buffer_geometry.rb +181 -0
  81. data/lib/three/core/clock.rb +58 -0
  82. data/lib/three/core/event_dispatcher.rb +57 -0
  83. data/lib/three/core/layers.rb +75 -0
  84. data/lib/three/core/object3d.rb +331 -0
  85. data/lib/three/core/raycaster.rb +73 -0
  86. data/lib/three/dirty.rb +58 -0
  87. data/lib/three/exporters/three_json_exporter.rb +187 -0
  88. data/lib/three/geometries/box_geometry.rb +97 -0
  89. data/lib/three/geometries/plane_geometry.rb +70 -0
  90. data/lib/three/geometries/sphere_geometry.rb +107 -0
  91. data/lib/three/lights/ambient_light.rb +12 -0
  92. data/lib/three/lights/directional_light.rb +38 -0
  93. data/lib/three/lights/hemisphere_light.rb +34 -0
  94. data/lib/three/lights/light.rb +85 -0
  95. data/lib/three/lights/point_light.rb +33 -0
  96. data/lib/three/loaders/cube_texture_loader.rb +13 -0
  97. data/lib/three/loaders/gltf_loader.rb +48 -0
  98. data/lib/three/loaders/rgbe_loader.rb +15 -0
  99. data/lib/three/loaders/texture_loader.rb +13 -0
  100. data/lib/three/loaders/three_json_loader.rb +409 -0
  101. data/lib/three/materials/line_basic_material.rb +65 -0
  102. data/lib/three/materials/material.rb +158 -0
  103. data/lib/three/materials/mesh_basic_material.rb +64 -0
  104. data/lib/three/materials/mesh_lambert_material.rb +71 -0
  105. data/lib/three/materials/mesh_matcap_material.rb +86 -0
  106. data/lib/three/materials/mesh_normal_material.rb +42 -0
  107. data/lib/three/materials/mesh_phong_material.rb +119 -0
  108. data/lib/three/materials/mesh_physical_material.rb +155 -0
  109. data/lib/three/materials/mesh_standard_material.rb +149 -0
  110. data/lib/three/materials/mesh_toon_material.rb +98 -0
  111. data/lib/three/materials/points_material.rb +74 -0
  112. data/lib/three/materials/shadow_material.rb +45 -0
  113. data/lib/three/materials/sprite_material.rb +75 -0
  114. data/lib/three/math/color.rb +133 -0
  115. data/lib/three/math/euler.rb +197 -0
  116. data/lib/three/math/math_utils.rb +36 -0
  117. data/lib/three/math/matrix3.rb +255 -0
  118. data/lib/three/math/matrix4.rb +448 -0
  119. data/lib/three/math/quaternion.rb +277 -0
  120. data/lib/three/math/vector2.rb +95 -0
  121. data/lib/three/math/vector3.rb +396 -0
  122. data/lib/three/objects/external_object3d.rb +28 -0
  123. data/lib/three/objects/group.rb +12 -0
  124. data/lib/three/objects/instanced_mesh.rb +110 -0
  125. data/lib/three/objects/line.rb +41 -0
  126. data/lib/three/objects/mesh.rb +45 -0
  127. data/lib/three/objects/points.rb +41 -0
  128. data/lib/three/objects/sprite.rb +57 -0
  129. data/lib/three/postprocessing/dot_screen_pass.rb +83 -0
  130. data/lib/three/postprocessing/effect_composer.rb +56 -0
  131. data/lib/three/postprocessing/output_pass.rb +40 -0
  132. data/lib/three/postprocessing/render_pass.rb +42 -0
  133. data/lib/three/postprocessing/unreal_bloom_pass.rb +56 -0
  134. data/lib/three/renderers/renderer.rb +11 -0
  135. data/lib/three/renderers/threejs_renderer.rb +85 -0
  136. data/lib/three/scenes/scene.rb +29 -0
  137. data/lib/three/textures/cube_texture.rb +72 -0
  138. data/lib/three/textures/rgbe_texture.rb +45 -0
  139. data/lib/three/textures/texture.rb +200 -0
  140. data/lib/three/version.rb +5 -0
  141. data/lib/three-rb.rb +3 -0
  142. data/lib/three.rb +77 -0
  143. data/package.json +30 -0
  144. data/pnpm-lock.yaml +86 -0
  145. metadata +216 -0
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../core/buffer_geometry"
4
+ require_relative "../materials/points_material"
5
+ require_relative "group"
6
+
7
+ module Three
8
+ class Points < Object3D
9
+ attr_reader :geometry, :material
10
+
11
+ def initialize(geometry = BufferGeometry.new, material = PointsMaterial.new)
12
+ super()
13
+ @type = "Points"
14
+ @geometry = nil
15
+ @material = nil
16
+ self.geometry = geometry
17
+ self.material = material
18
+ end
19
+
20
+ def geometry=(value)
21
+ @geometry.remove_dirty_dependent(self) if @geometry.respond_to?(:remove_dirty_dependent)
22
+ @geometry = value
23
+ @geometry.add_dirty_dependent(self) if @geometry.respond_to?(:add_dirty_dependent)
24
+ mark_dirty!(:points)
25
+ end
26
+
27
+ def material=(value)
28
+ @material.remove_dirty_dependent(self) if @material.respond_to?(:remove_dirty_dependent)
29
+ @material = value
30
+ @material.add_dirty_dependent(self) if @material.respond_to?(:add_dirty_dependent)
31
+ mark_dirty!(:points)
32
+ end
33
+
34
+ def to_h
35
+ super.merge(
36
+ geometry: @geometry.uuid,
37
+ material: @material.respond_to?(:uuid) ? @material.uuid : nil
38
+ )
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../materials/sprite_material"
4
+ require_relative "../math/vector2"
5
+ require_relative "group"
6
+
7
+ module Three
8
+ class Sprite < Object3D
9
+ attr_reader :material, :center
10
+
11
+ def initialize(material = SpriteMaterial.new)
12
+ super()
13
+ @type = "Sprite"
14
+ @material = nil
15
+ @center = Vector2.new(0.5, 0.5)
16
+ bind_center_changes
17
+ self.material = material
18
+ end
19
+
20
+ def material=(value)
21
+ @material.remove_dirty_dependent(self) if @material.respond_to?(:remove_dirty_dependent)
22
+ @material = value
23
+ @material.add_dirty_dependent(self) if @material.respond_to?(:add_dirty_dependent)
24
+ mark_dirty!(:sprite)
25
+ end
26
+
27
+ def center=(value)
28
+ @center = coerce_center(value)
29
+ bind_center_changes
30
+ mark_dirty!(:sprite)
31
+ end
32
+
33
+ def to_h
34
+ super.merge(
35
+ material: @material.respond_to?(:uuid) ? @material.uuid : nil,
36
+ center: @center.to_a
37
+ )
38
+ end
39
+
40
+ private
41
+
42
+ def coerce_center(value)
43
+ return value if value.is_a?(Vector2)
44
+
45
+ if value.respond_to?(:to_a)
46
+ array = value.to_a
47
+ return Vector2.new(array[0], array[1]) if array.length == 2
48
+ end
49
+
50
+ raise TypeError, "center must be a Three::Vector2 or an array-like [x, y]"
51
+ end
52
+
53
+ def bind_center_changes
54
+ @center.on_change { mark_dirty!(:sprite) }
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../backends/threejs"
4
+ require_relative "../math/vector2"
5
+
6
+ module Three
7
+ module Postprocessing
8
+ class DotScreenPass
9
+ PROPERTY_NAMES = {
10
+ enabled: "enabled"
11
+ }.freeze
12
+
13
+ attr_reader :backend, :handle, :center, :angle, :scale
14
+ attr_reader(*PROPERTY_NAMES.keys)
15
+
16
+ def initialize(center: [0.5, 0.5], angle: 1.57, scale: 1, backend: nil, composer: nil, **parameters)
17
+ @backend = backend || composer&.backend || Backends::ThreeJS.new
18
+ @center = coerce_center(center)
19
+ @angle = angle
20
+ @scale = scale
21
+ @enabled = true
22
+ @handle = @backend.create_dot_screen_pass(@center.to_a, @angle, @scale)
23
+ bind_center_changes
24
+ set_values(parameters)
25
+ end
26
+
27
+ PROPERTY_NAMES.each do |ruby_name, js_name|
28
+ define_method("#{ruby_name}=") do |value|
29
+ instance_variable_set("@#{ruby_name}", value)
30
+ @backend.set_postprocessing_pass_property(@handle, js_name, value) if @handle
31
+ value
32
+ end
33
+ end
34
+
35
+ def center=(value)
36
+ @center = coerce_center(value)
37
+ bind_center_changes
38
+ sync_uniform("center", @center.to_a)
39
+ @center
40
+ end
41
+
42
+ def angle=(value)
43
+ @angle = value
44
+ sync_uniform("angle", value)
45
+ value
46
+ end
47
+
48
+ def scale=(value)
49
+ @scale = value
50
+ sync_uniform("scale", value)
51
+ value
52
+ end
53
+
54
+ private
55
+
56
+ def coerce_center(value)
57
+ return value if value.is_a?(Vector2)
58
+
59
+ if value.respond_to?(:to_a)
60
+ array = value.to_a
61
+ return Vector2.new(array[0], array[1]) if array.length == 2
62
+ end
63
+
64
+ raise TypeError, "center must be a Three::Vector2 or an array-like [x, y]"
65
+ end
66
+
67
+ def bind_center_changes
68
+ @center.on_change { sync_uniform("center", @center.to_a) }
69
+ end
70
+
71
+ def sync_uniform(name, value)
72
+ @backend.set_postprocessing_pass_uniform(@handle, name, value) if @handle
73
+ end
74
+
75
+ def set_values(parameters)
76
+ parameters.each do |key, value|
77
+ setter = "#{key}="
78
+ public_send(setter, value) if respond_to?(setter)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../backends/threejs"
4
+
5
+ module Three
6
+ module Postprocessing
7
+ class EffectComposer
8
+ attr_reader :renderer, :backend, :handle, :passes
9
+
10
+ def initialize(renderer:, backend: nil)
11
+ @renderer = renderer
12
+ renderer_backend = renderer.backend if renderer.respond_to?(:backend)
13
+ @backend = backend || renderer_backend
14
+ raise ArgumentError, "renderer must expose a backend or backend must be provided" unless @backend
15
+ if renderer_backend && !renderer_backend.equal?(@backend)
16
+ raise ArgumentError, "effect composer backend must match the renderer backend"
17
+ end
18
+
19
+ @handle = @backend.create_effect_composer(renderer.handle)
20
+ @passes = []
21
+ end
22
+
23
+ def add_pass(pass)
24
+ ensure_pass_backend!(pass)
25
+ @passes << pass
26
+ @backend.add_effect_composer_pass(@handle, pass.handle)
27
+ self
28
+ end
29
+
30
+ def set_size(width, height)
31
+ @backend.set_effect_composer_size(@handle, width, height)
32
+ self
33
+ end
34
+
35
+ def render(scene = nil, camera = nil)
36
+ scene.update_matrix_world if scene.respond_to?(:update_matrix_world)
37
+ camera.update_matrix_world if camera.respond_to?(:update_matrix_world) && camera.parent.nil?
38
+ @backend.render_effect_composer(@handle, scene, camera)
39
+ self
40
+ end
41
+
42
+ def dispose
43
+ @backend.dispose_effect_composer(@handle)
44
+ self
45
+ end
46
+
47
+ private
48
+
49
+ def ensure_pass_backend!(pass)
50
+ return if pass.respond_to?(:backend) && pass.backend.equal?(@backend)
51
+
52
+ raise ArgumentError, "postprocessing pass must use the same backend as the composer"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../backends/threejs"
4
+
5
+ module Three
6
+ module Postprocessing
7
+ class OutputPass
8
+ PROPERTY_NAMES = {
9
+ enabled: "enabled"
10
+ }.freeze
11
+
12
+ attr_reader :backend, :handle
13
+ attr_reader(*PROPERTY_NAMES.keys)
14
+
15
+ def initialize(backend: nil, composer: nil, **parameters)
16
+ @backend = backend || composer&.backend || Backends::ThreeJS.new
17
+ @enabled = true
18
+ @handle = @backend.create_output_pass
19
+ set_values(parameters)
20
+ end
21
+
22
+ PROPERTY_NAMES.each do |ruby_name, js_name|
23
+ define_method("#{ruby_name}=") do |value|
24
+ instance_variable_set("@#{ruby_name}", value)
25
+ @backend.set_postprocessing_pass_property(@handle, js_name, value) if @handle
26
+ value
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def set_values(parameters)
33
+ parameters.each do |key, value|
34
+ setter = "#{key}="
35
+ public_send(setter, value) if respond_to?(setter)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../backends/threejs"
4
+
5
+ module Three
6
+ module Postprocessing
7
+ class RenderPass
8
+ PROPERTY_NAMES = {
9
+ enabled: "enabled"
10
+ }.freeze
11
+
12
+ attr_reader :scene, :camera, :backend, :handle
13
+ attr_reader(*PROPERTY_NAMES.keys)
14
+
15
+ def initialize(scene, camera, backend: nil, composer: nil, **parameters)
16
+ @scene = scene
17
+ @camera = camera
18
+ @backend = backend || composer&.backend || Backends::ThreeJS.new
19
+ @enabled = true
20
+ @handle = @backend.create_render_pass(scene, camera)
21
+ set_values(parameters)
22
+ end
23
+
24
+ PROPERTY_NAMES.each do |ruby_name, js_name|
25
+ define_method("#{ruby_name}=") do |value|
26
+ instance_variable_set("@#{ruby_name}", value)
27
+ @backend.set_postprocessing_pass_property(@handle, js_name, value) if @handle
28
+ value
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def set_values(parameters)
35
+ parameters.each do |key, value|
36
+ setter = "#{key}="
37
+ public_send(setter, value) if respond_to?(setter)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../backends/threejs"
4
+
5
+ module Three
6
+ module Postprocessing
7
+ class UnrealBloomPass
8
+ PROPERTY_NAMES = {
9
+ enabled: "enabled",
10
+ strength: "strength",
11
+ radius: "radius",
12
+ threshold: "threshold"
13
+ }.freeze
14
+
15
+ attr_reader :backend, :handle, :resolution
16
+ attr_reader(*PROPERTY_NAMES.keys)
17
+
18
+ def initialize(resolution: [1, 1], strength: 1, radius: 0, threshold: 0, backend: nil, composer: nil, **parameters)
19
+ @backend = backend || composer&.backend || Backends::ThreeJS.new
20
+ @resolution = coerce_resolution(resolution)
21
+ @enabled = true
22
+ @strength = strength
23
+ @radius = radius
24
+ @threshold = threshold
25
+ @handle = @backend.create_unreal_bloom_pass(@resolution, @strength, @radius, @threshold)
26
+ set_values(parameters)
27
+ end
28
+
29
+ PROPERTY_NAMES.each do |ruby_name, js_name|
30
+ define_method("#{ruby_name}=") do |value|
31
+ instance_variable_set("@#{ruby_name}", value)
32
+ @backend.set_postprocessing_pass_property(@handle, js_name, value) if @handle
33
+ value
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def coerce_resolution(value)
40
+ if value.respond_to?(:to_a)
41
+ result = value.to_a
42
+ return result if result.length == 2
43
+ end
44
+
45
+ raise TypeError, "resolution must be an array-like [width, height]"
46
+ end
47
+
48
+ def set_values(parameters)
49
+ parameters.each do |key, value|
50
+ setter = "#{key}="
51
+ public_send(setter, value) if respond_to?(setter)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Three
4
+ module Renderers
5
+ class Renderer
6
+ def render(_scene, _camera)
7
+ raise NotImplementedError
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../backends/threejs"
4
+ require_relative "renderer"
5
+
6
+ module Three
7
+ module Renderers
8
+ class ThreeJSRenderer < Renderer
9
+ attr_reader :backend, :handle
10
+
11
+ def initialize(canvas: nil, backend: Backends::ThreeJS.new, **options)
12
+ shadow_map_enabled = options.delete(:shadow_map_enabled)
13
+ shadow_map_type = options.delete(:shadow_map_type)
14
+ shadow_map_auto_update = options.delete(:shadow_map_auto_update)
15
+ @backend = backend
16
+ @handle = @backend.create_renderer(canvas: canvas, **options)
17
+ if [shadow_map_enabled, shadow_map_type, shadow_map_auto_update].any?
18
+ configure_shadow_map(enabled: shadow_map_enabled, type: shadow_map_type, auto_update: shadow_map_auto_update)
19
+ end
20
+ end
21
+
22
+ def set_size(width, height)
23
+ @backend.set_renderer_size(@handle, width, height)
24
+ self
25
+ end
26
+
27
+ def dom_element
28
+ @backend.renderer_dom_element(@handle)
29
+ end
30
+
31
+ def set_clear_color(color, alpha = 1)
32
+ @backend.set_clear_color(@handle, color, alpha)
33
+ self
34
+ end
35
+
36
+ def configure_shadow_map(enabled: nil, type: nil, auto_update: nil)
37
+ @backend.set_renderer_shadow_map(@handle, enabled: enabled, type: type, auto_update: auto_update)
38
+ self
39
+ end
40
+
41
+ def animation_loop(&block)
42
+ @backend.set_animation_loop(@handle, block)
43
+ self
44
+ end
45
+
46
+ def render(scene, camera)
47
+ scene.update_matrix_world if scene.respond_to?(:update_matrix_world)
48
+ camera.update_matrix_world if camera.respond_to?(:update_matrix_world) && camera.parent.nil?
49
+ @backend.render(@handle, scene, camera)
50
+ self
51
+ end
52
+
53
+ def dispose(object, **options)
54
+ @backend.dispose(object, **options)
55
+ self
56
+ end
57
+
58
+ def traverse_handles(object, &block)
59
+ return enum_for(:traverse_handles, object) unless block
60
+
61
+ @backend.traverse_handles(object, &block)
62
+ self
63
+ end
64
+
65
+ def dispose_subtree(
66
+ object,
67
+ remove: true,
68
+ dispose_geometries: true,
69
+ dispose_materials: true,
70
+ dispose_textures: true,
71
+ dispose_skeletons: true
72
+ )
73
+ @backend.dispose_subtree(
74
+ object,
75
+ remove: remove,
76
+ dispose_geometries: dispose_geometries,
77
+ dispose_materials: dispose_materials,
78
+ dispose_textures: dispose_textures,
79
+ dispose_skeletons: dispose_skeletons
80
+ )
81
+ self
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../core/object3d"
4
+
5
+ module Three
6
+ class Scene < Object3D
7
+ attr_reader :background, :environment
8
+ attr_accessor :fog, :override_material
9
+
10
+ def initialize
11
+ super
12
+ @type = "Scene"
13
+ @background = nil
14
+ @environment = nil
15
+ @fog = nil
16
+ @override_material = nil
17
+ end
18
+
19
+ def background=(value)
20
+ @background = value
21
+ mark_dirty!(:scene)
22
+ end
23
+
24
+ def environment=(value)
25
+ @environment = value
26
+ mark_dirty!(:scene)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "texture"
4
+
5
+ module Three
6
+ class CubeTexture < Texture
7
+ FACE_COUNT = 6
8
+
9
+ def initialize(
10
+ sources,
11
+ mapping: Three::CubeReflectionMapping,
12
+ color_space: Three::NoColorSpace,
13
+ flip_y: false,
14
+ wrap_s: Three::ClampToEdgeWrapping,
15
+ wrap_t: Three::ClampToEdgeWrapping,
16
+ mag_filter: Three::LinearFilter,
17
+ min_filter: Three::LinearMipmapLinearFilter,
18
+ offset: nil,
19
+ repeat: nil,
20
+ center: nil,
21
+ rotation: 0,
22
+ matrix_auto_update: true,
23
+ matrix: nil
24
+ )
25
+ super(
26
+ validate_sources(sources),
27
+ mapping: mapping,
28
+ color_space: color_space,
29
+ flip_y: flip_y,
30
+ wrap_s: wrap_s,
31
+ wrap_t: wrap_t,
32
+ mag_filter: mag_filter,
33
+ min_filter: min_filter,
34
+ offset: offset,
35
+ repeat: repeat,
36
+ center: center,
37
+ rotation: rotation,
38
+ matrix_auto_update: matrix_auto_update,
39
+ matrix: matrix
40
+ )
41
+ end
42
+
43
+ def sources
44
+ source
45
+ end
46
+
47
+ def sources=(value)
48
+ self.source = value
49
+ end
50
+
51
+ def source=(value)
52
+ super(validate_sources(value))
53
+ end
54
+
55
+ def to_h
56
+ super.merge(type: "CubeTexture", sources: sources)
57
+ end
58
+
59
+ private
60
+
61
+ def validate_sources(value)
62
+ array = value.to_ary if value.respond_to?(:to_ary)
63
+ array ||= value.to_a if value.respond_to?(:to_a)
64
+
65
+ unless array&.length == FACE_COUNT
66
+ raise ArgumentError, "cube texture sources must contain six image sources"
67
+ end
68
+
69
+ array.dup
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "texture"
4
+
5
+ module Three
6
+ class RGBETexture < Texture
7
+ def initialize(
8
+ source,
9
+ mapping: Three::EquirectangularReflectionMapping,
10
+ color_space: Three::LinearSRGBColorSpace,
11
+ flip_y: true,
12
+ wrap_s: Three::ClampToEdgeWrapping,
13
+ wrap_t: Three::ClampToEdgeWrapping,
14
+ mag_filter: Three::LinearFilter,
15
+ min_filter: Three::LinearFilter,
16
+ offset: nil,
17
+ repeat: nil,
18
+ center: nil,
19
+ rotation: 0,
20
+ matrix_auto_update: true,
21
+ matrix: nil
22
+ )
23
+ super(
24
+ source,
25
+ mapping: mapping,
26
+ color_space: color_space,
27
+ flip_y: flip_y,
28
+ wrap_s: wrap_s,
29
+ wrap_t: wrap_t,
30
+ mag_filter: mag_filter,
31
+ min_filter: min_filter,
32
+ offset: offset,
33
+ repeat: repeat,
34
+ center: center,
35
+ rotation: rotation,
36
+ matrix_auto_update: matrix_auto_update,
37
+ matrix: matrix
38
+ )
39
+ end
40
+
41
+ def to_h
42
+ super.merge(type: "RGBETexture")
43
+ end
44
+ end
45
+ end