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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +19 -0
- data/LICENSE +21 -0
- data/README.md +153 -0
- data/docs/browser-runtime.md +153 -0
- data/docs/implementation-plan.md +874 -0
- data/docs/loaded-assets-design.md +400 -0
- data/docs/next-work.md +107 -0
- data/docs/publishing.md +64 -0
- data/docs/release-readiness.md +83 -0
- data/examples/browser/README.md +54 -0
- data/examples/browser/assets/animated_triangle.gltf +123 -0
- data/examples/browser/assets/checker.svg +11 -0
- data/examples/browser/assets/compressed_triangle.gltf +74 -0
- data/examples/browser/assets/studio.hdr +5 -0
- data/examples/browser/assets/triangle.gltf +67 -0
- data/examples/browser/composition/README.md +35 -0
- data/examples/browser/composition/boot.mjs +6 -0
- data/examples/browser/composition/index.html +136 -0
- data/examples/browser/composition/main.rb +216 -0
- data/examples/browser/composition/smoke_test.mjs +266 -0
- data/examples/browser/cube/README.md +41 -0
- data/examples/browser/cube/boot.mjs +6 -0
- data/examples/browser/cube/index.html +142 -0
- data/examples/browser/cube/main.rb +62 -0
- data/examples/browser/cube/smoke_test.mjs +99 -0
- data/examples/browser/cubemap/README.md +23 -0
- data/examples/browser/cubemap/boot.mjs +6 -0
- data/examples/browser/cubemap/index.html +142 -0
- data/examples/browser/cubemap/main.rb +84 -0
- data/examples/browser/cubemap/smoke_test.mjs +91 -0
- data/examples/browser/gltf/README.md +23 -0
- data/examples/browser/gltf/boot.mjs +6 -0
- data/examples/browser/gltf/index.html +142 -0
- data/examples/browser/gltf/main.rb +105 -0
- data/examples/browser/gltf/smoke_test.mjs +162 -0
- data/examples/browser/picking/README.md +33 -0
- data/examples/browser/picking/boot.mjs +6 -0
- data/examples/browser/picking/index.html +142 -0
- data/examples/browser/picking/main.rb +113 -0
- data/examples/browser/picking/smoke_test.mjs +78 -0
- data/examples/browser/postprocessing/README.md +26 -0
- data/examples/browser/postprocessing/boot.mjs +6 -0
- data/examples/browser/postprocessing/index.html +142 -0
- data/examples/browser/postprocessing/main.rb +117 -0
- data/examples/browser/postprocessing/smoke_test.mjs +121 -0
- data/examples/browser/primitives/README.md +33 -0
- data/examples/browser/primitives/boot.mjs +6 -0
- data/examples/browser/primitives/index.html +142 -0
- data/examples/browser/primitives/main.rb +116 -0
- data/examples/browser/primitives/smoke_test.mjs +113 -0
- data/examples/browser/serialization/README.md +33 -0
- data/examples/browser/serialization/boot.mjs +6 -0
- data/examples/browser/serialization/index.html +142 -0
- data/examples/browser/serialization/main.rb +97 -0
- data/examples/browser/serialization/smoke_test.mjs +67 -0
- data/examples/browser/shared/boot.mjs +79 -0
- data/examples/browser/shared/smoke_test_helpers.mjs +151 -0
- data/examples/browser/textures/README.md +35 -0
- data/examples/browser/textures/boot.mjs +6 -0
- data/examples/browser/textures/index.html +142 -0
- data/examples/browser/textures/main.rb +142 -0
- data/examples/browser/textures/smoke_test.mjs +189 -0
- data/lib/three/animation/animation_action.rb +57 -0
- data/lib/three/animation/animation_clip.rb +22 -0
- data/lib/three/animation/animation_mixer.rb +43 -0
- data/lib/three/backends/base.rb +87 -0
- data/lib/three/backends/threejs/materialization.rb +143 -0
- data/lib/three/backends/threejs/parameters.rb +97 -0
- data/lib/three/backends/threejs/resource_management.rb +69 -0
- data/lib/three/backends/threejs/ruby_wasm_adapter.rb +873 -0
- data/lib/three/backends/threejs/synchronization.rb +224 -0
- data/lib/three/backends/threejs.rb +365 -0
- data/lib/three/cameras/camera.rb +39 -0
- data/lib/three/cameras/orthographic_camera.rb +107 -0
- data/lib/three/cameras/perspective_camera.rb +137 -0
- data/lib/three/constants.rb +40 -0
- data/lib/three/controls/orbit_controls.rb +118 -0
- data/lib/three/core/buffer_attribute.rb +151 -0
- data/lib/three/core/buffer_geometry.rb +181 -0
- data/lib/three/core/clock.rb +58 -0
- data/lib/three/core/event_dispatcher.rb +57 -0
- data/lib/three/core/layers.rb +75 -0
- data/lib/three/core/object3d.rb +331 -0
- data/lib/three/core/raycaster.rb +73 -0
- data/lib/three/dirty.rb +58 -0
- data/lib/three/exporters/three_json_exporter.rb +187 -0
- data/lib/three/geometries/box_geometry.rb +97 -0
- data/lib/three/geometries/plane_geometry.rb +70 -0
- data/lib/three/geometries/sphere_geometry.rb +107 -0
- data/lib/three/lights/ambient_light.rb +12 -0
- data/lib/three/lights/directional_light.rb +38 -0
- data/lib/three/lights/hemisphere_light.rb +34 -0
- data/lib/three/lights/light.rb +85 -0
- data/lib/three/lights/point_light.rb +33 -0
- data/lib/three/loaders/cube_texture_loader.rb +13 -0
- data/lib/three/loaders/gltf_loader.rb +48 -0
- data/lib/three/loaders/rgbe_loader.rb +15 -0
- data/lib/three/loaders/texture_loader.rb +13 -0
- data/lib/three/loaders/three_json_loader.rb +409 -0
- data/lib/three/materials/line_basic_material.rb +65 -0
- data/lib/three/materials/material.rb +158 -0
- data/lib/three/materials/mesh_basic_material.rb +64 -0
- data/lib/three/materials/mesh_lambert_material.rb +71 -0
- data/lib/three/materials/mesh_matcap_material.rb +86 -0
- data/lib/three/materials/mesh_normal_material.rb +42 -0
- data/lib/three/materials/mesh_phong_material.rb +119 -0
- data/lib/three/materials/mesh_physical_material.rb +155 -0
- data/lib/three/materials/mesh_standard_material.rb +149 -0
- data/lib/three/materials/mesh_toon_material.rb +98 -0
- data/lib/three/materials/points_material.rb +74 -0
- data/lib/three/materials/shadow_material.rb +45 -0
- data/lib/three/materials/sprite_material.rb +75 -0
- data/lib/three/math/color.rb +133 -0
- data/lib/three/math/euler.rb +197 -0
- data/lib/three/math/math_utils.rb +36 -0
- data/lib/three/math/matrix3.rb +255 -0
- data/lib/three/math/matrix4.rb +448 -0
- data/lib/three/math/quaternion.rb +277 -0
- data/lib/three/math/vector2.rb +95 -0
- data/lib/three/math/vector3.rb +396 -0
- data/lib/three/objects/external_object3d.rb +28 -0
- data/lib/three/objects/group.rb +12 -0
- data/lib/three/objects/instanced_mesh.rb +110 -0
- data/lib/three/objects/line.rb +41 -0
- data/lib/three/objects/mesh.rb +45 -0
- data/lib/three/objects/points.rb +41 -0
- data/lib/three/objects/sprite.rb +57 -0
- data/lib/three/postprocessing/dot_screen_pass.rb +83 -0
- data/lib/three/postprocessing/effect_composer.rb +56 -0
- data/lib/three/postprocessing/output_pass.rb +40 -0
- data/lib/three/postprocessing/render_pass.rb +42 -0
- data/lib/three/postprocessing/unreal_bloom_pass.rb +56 -0
- data/lib/three/renderers/renderer.rb +11 -0
- data/lib/three/renderers/threejs_renderer.rb +85 -0
- data/lib/three/scenes/scene.rb +29 -0
- data/lib/three/textures/cube_texture.rb +72 -0
- data/lib/three/textures/rgbe_texture.rb +45 -0
- data/lib/three/textures/texture.rb +200 -0
- data/lib/three/version.rb +5 -0
- data/lib/three-rb.rb +3 -0
- data/lib/three.rb +77 -0
- data/package.json +30 -0
- data/pnpm-lock.yaml +86 -0
- 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,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
|