3rb 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/.rspec +2 -0
- data/3rb.gemspec +29 -0
- data/CHANGELOG.md +12 -0
- data/LICENSE +21 -0
- data/README.md +321 -0
- data/Rakefile +13 -0
- data/examples/01_hello_cube.rb +29 -0
- data/examples/02_basic_geometries.rb +56 -0
- data/examples/03_materials.rb +61 -0
- data/examples/04_lighting.rb +63 -0
- data/examples/05_animation.rb +79 -0
- data/examples/06_custom_shader.rb +92 -0
- data/examples/07_scene_graph.rb +74 -0
- data/examples/08_orbit_controls.rb +50 -0
- data/examples/09_3d_chart.rb +71 -0
- data/examples/10_procedural_terrain.rb +140 -0
- data/examples/11_particle_system.rb +68 -0
- data/examples/12_model_loader.rb +73 -0
- data/examples/13_game_prototype.rb +145 -0
- data/examples/14_utah_teapot.rb +291 -0
- data/examples/15_stanford_bunny.rb +200 -0
- data/examples/16_cornell_box.rb +373 -0
- data/examples/17_weird_fractal4.rb +130 -0
- data/examples/18_platonic_solids.rb +268 -0
- data/lib/3rb/animation/animation_clip.rb +287 -0
- data/lib/3rb/animation/animation_mixer.rb +366 -0
- data/lib/3rb/cameras/camera.rb +50 -0
- data/lib/3rb/cameras/orthographic_camera.rb +92 -0
- data/lib/3rb/cameras/perspective_camera.rb +103 -0
- data/lib/3rb/controls/orbit_controls.rb +341 -0
- data/lib/3rb/core/buffer_attribute.rb +172 -0
- data/lib/3rb/core/group.rb +9 -0
- data/lib/3rb/core/object3d.rb +298 -0
- data/lib/3rb/core/scene.rb +78 -0
- data/lib/3rb/dsl/helpers.rb +57 -0
- data/lib/3rb/dsl/scene_builder.rb +288 -0
- data/lib/3rb/ffi/glfw.rb +61 -0
- data/lib/3rb/ffi/opengl.rb +137 -0
- data/lib/3rb/ffi/platform.rb +65 -0
- data/lib/3rb/geometries/box_geometry.rb +101 -0
- data/lib/3rb/geometries/buffer_geometry.rb +345 -0
- data/lib/3rb/geometries/cone_geometry.rb +29 -0
- data/lib/3rb/geometries/cylinder_geometry.rb +149 -0
- data/lib/3rb/geometries/plane_geometry.rb +75 -0
- data/lib/3rb/geometries/sphere_geometry.rb +93 -0
- data/lib/3rb/geometries/torus_geometry.rb +77 -0
- data/lib/3rb/lights/ambient_light.rb +9 -0
- data/lib/3rb/lights/directional_light.rb +57 -0
- data/lib/3rb/lights/hemisphere_light.rb +26 -0
- data/lib/3rb/lights/light.rb +27 -0
- data/lib/3rb/lights/point_light.rb +68 -0
- data/lib/3rb/lights/rect_area_light.rb +35 -0
- data/lib/3rb/lights/spot_light.rb +88 -0
- data/lib/3rb/loaders/gltf_loader.rb +304 -0
- data/lib/3rb/loaders/loader.rb +94 -0
- data/lib/3rb/loaders/obj_loader.rb +186 -0
- data/lib/3rb/loaders/texture_loader.rb +55 -0
- data/lib/3rb/materials/basic_material.rb +70 -0
- data/lib/3rb/materials/lambert_material.rb +102 -0
- data/lib/3rb/materials/material.rb +114 -0
- data/lib/3rb/materials/phong_material.rb +106 -0
- data/lib/3rb/materials/shader_material.rb +104 -0
- data/lib/3rb/materials/standard_material.rb +106 -0
- data/lib/3rb/math/color.rb +246 -0
- data/lib/3rb/math/euler.rb +156 -0
- data/lib/3rb/math/math_utils.rb +132 -0
- data/lib/3rb/math/matrix3.rb +269 -0
- data/lib/3rb/math/matrix4.rb +501 -0
- data/lib/3rb/math/quaternion.rb +337 -0
- data/lib/3rb/math/vector2.rb +216 -0
- data/lib/3rb/math/vector3.rb +366 -0
- data/lib/3rb/math/vector4.rb +233 -0
- data/lib/3rb/native/gl.rb +382 -0
- data/lib/3rb/native/native.rb +55 -0
- data/lib/3rb/native/window.rb +111 -0
- data/lib/3rb/native.rb +9 -0
- data/lib/3rb/objects/line.rb +116 -0
- data/lib/3rb/objects/mesh.rb +40 -0
- data/lib/3rb/objects/points.rb +71 -0
- data/lib/3rb/renderers/opengl_renderer.rb +567 -0
- data/lib/3rb/renderers/renderer.rb +60 -0
- data/lib/3rb/renderers/shader_lib.rb +100 -0
- data/lib/3rb/textures/cube_texture.rb +26 -0
- data/lib/3rb/textures/data_texture.rb +35 -0
- data/lib/3rb/textures/render_target.rb +125 -0
- data/lib/3rb/textures/texture.rb +190 -0
- data/lib/3rb/version.rb +5 -0
- data/lib/3rb.rb +86 -0
- data/shaders/basic.frag +19 -0
- data/shaders/basic.vert +15 -0
- data/shaders/common/lights.glsl +53 -0
- data/shaders/common/uniforms.glsl +9 -0
- data/shaders/lambert.frag +37 -0
- data/shaders/lambert.vert +22 -0
- data/shaders/phong.frag +51 -0
- data/shaders/phong.vert +28 -0
- data/shaders/standard.frag +92 -0
- data/shaders/standard.vert +28 -0
- metadata +155 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sunrb
|
|
4
|
+
module ShaderLib
|
|
5
|
+
SHADERS_PATH = File.expand_path("../../../shaders", __dir__)
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
def load_shader(name)
|
|
9
|
+
{
|
|
10
|
+
vertex_shader: load_file("#{name}.vert"),
|
|
11
|
+
fragment_shader: load_file("#{name}.frag")
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def basic
|
|
16
|
+
@basic ||= load_shader("basic").merge(
|
|
17
|
+
uniforms: basic_uniforms
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def lambert
|
|
22
|
+
@lambert ||= load_shader("lambert").merge(
|
|
23
|
+
uniforms: lambert_uniforms
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def phong
|
|
28
|
+
@phong ||= load_shader("phong").merge(
|
|
29
|
+
uniforms: phong_uniforms
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def standard
|
|
34
|
+
@standard ||= load_shader("standard").merge(
|
|
35
|
+
uniforms: standard_uniforms
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def load_file(filename)
|
|
42
|
+
path = File.join(SHADERS_PATH, filename)
|
|
43
|
+
return nil unless File.exist?(path)
|
|
44
|
+
|
|
45
|
+
File.read(path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def common_uniforms
|
|
49
|
+
{
|
|
50
|
+
model_matrix: { type: :mat4, value: nil },
|
|
51
|
+
model_view_matrix: { type: :mat4, value: nil },
|
|
52
|
+
projection_matrix: { type: :mat4, value: nil },
|
|
53
|
+
view_matrix: { type: :mat4, value: nil },
|
|
54
|
+
normal_matrix: { type: :mat3, value: nil },
|
|
55
|
+
camera_position: { type: :vec3, value: Vector3.new }
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def basic_uniforms
|
|
60
|
+
common_uniforms.merge(
|
|
61
|
+
diffuse: { type: :vec3, value: Color.new(0xffffff) },
|
|
62
|
+
opacity: { type: :float, value: 1.0 },
|
|
63
|
+
map: { type: :texture, value: nil },
|
|
64
|
+
use_map: { type: :bool, value: false }
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def lambert_uniforms
|
|
69
|
+
basic_uniforms.merge(
|
|
70
|
+
emissive: { type: :vec3, value: Color.new(0x000000) },
|
|
71
|
+
ambient_light_color: { type: :vec3, value: Color.new(0x000000) },
|
|
72
|
+
directional_light_direction: { type: :vec3, value: Vector3.new(0, 1, 0) },
|
|
73
|
+
directional_light_color: { type: :vec3, value: Color.new(0xffffff) }
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def phong_uniforms
|
|
78
|
+
lambert_uniforms.merge(
|
|
79
|
+
specular: { type: :vec3, value: Color.new(0x111111) },
|
|
80
|
+
shininess: { type: :float, value: 30.0 }
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def standard_uniforms
|
|
85
|
+
common_uniforms.merge(
|
|
86
|
+
diffuse: { type: :vec3, value: Color.new(0xffffff) },
|
|
87
|
+
emissive: { type: :vec3, value: Color.new(0x000000) },
|
|
88
|
+
roughness: { type: :float, value: 1.0 },
|
|
89
|
+
metalness: { type: :float, value: 0.0 },
|
|
90
|
+
opacity: { type: :float, value: 1.0 },
|
|
91
|
+
map: { type: :texture, value: nil },
|
|
92
|
+
use_map: { type: :bool, value: false },
|
|
93
|
+
ambient_light_color: { type: :vec3, value: Color.new(0x000000) },
|
|
94
|
+
directional_light_direction: { type: :vec3, value: Vector3.new(0, 1, 0) },
|
|
95
|
+
directional_light_color: { type: :vec3, value: Color.new(0xffffff) }
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sunrb
|
|
4
|
+
class CubeTexture < Texture
|
|
5
|
+
attr_accessor :images
|
|
6
|
+
|
|
7
|
+
def initialize(
|
|
8
|
+
images: Array.new(6),
|
|
9
|
+
mapping: :cube_reflection,
|
|
10
|
+
**options
|
|
11
|
+
)
|
|
12
|
+
super(mapping: mapping, **options)
|
|
13
|
+
|
|
14
|
+
@images = images
|
|
15
|
+
@flip_y = false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def image
|
|
19
|
+
@images
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def image=(value)
|
|
23
|
+
@images = value
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sunrb
|
|
4
|
+
class DataTexture < Texture
|
|
5
|
+
attr_accessor :data, :width, :height
|
|
6
|
+
|
|
7
|
+
def initialize(
|
|
8
|
+
data: nil,
|
|
9
|
+
width: 1,
|
|
10
|
+
height: 1,
|
|
11
|
+
format: :rgba,
|
|
12
|
+
type: :unsigned_byte,
|
|
13
|
+
**options
|
|
14
|
+
)
|
|
15
|
+
super(format: format, type: type, **options)
|
|
16
|
+
|
|
17
|
+
@data = data
|
|
18
|
+
@width = width
|
|
19
|
+
@height = height
|
|
20
|
+
|
|
21
|
+
@mag_filter = :nearest
|
|
22
|
+
@min_filter = :nearest
|
|
23
|
+
|
|
24
|
+
@generate_mipmaps = false
|
|
25
|
+
@flip_y = false
|
|
26
|
+
@unpack_alignment = 1
|
|
27
|
+
|
|
28
|
+
@needs_update = true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def image
|
|
32
|
+
{ data: @data, width: @width, height: @height }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sunrb
|
|
4
|
+
class RenderTarget
|
|
5
|
+
attr_accessor :uuid, :width, :height, :depth
|
|
6
|
+
attr_accessor :scissor, :scissor_test
|
|
7
|
+
attr_accessor :viewport
|
|
8
|
+
attr_accessor :texture, :depth_buffer, :stencil_buffer
|
|
9
|
+
attr_accessor :depth_texture
|
|
10
|
+
|
|
11
|
+
def initialize(
|
|
12
|
+
width: 1,
|
|
13
|
+
height: 1,
|
|
14
|
+
depth: 1,
|
|
15
|
+
min_filter: :linear,
|
|
16
|
+
mag_filter: :linear,
|
|
17
|
+
wrap_s: :clamp_to_edge,
|
|
18
|
+
wrap_t: :clamp_to_edge,
|
|
19
|
+
generate_mipmaps: false,
|
|
20
|
+
format: :rgba,
|
|
21
|
+
type: :unsigned_byte,
|
|
22
|
+
anisotropy: 1,
|
|
23
|
+
encoding: :linear,
|
|
24
|
+
depth_buffer: true,
|
|
25
|
+
stencil_buffer: false,
|
|
26
|
+
depth_texture: nil
|
|
27
|
+
)
|
|
28
|
+
@uuid = SecureRandom.uuid
|
|
29
|
+
@width = width
|
|
30
|
+
@height = height
|
|
31
|
+
@depth = depth
|
|
32
|
+
|
|
33
|
+
@scissor = Vector4.new(0, 0, width, height)
|
|
34
|
+
@scissor_test = false
|
|
35
|
+
|
|
36
|
+
@viewport = Vector4.new(0, 0, width, height)
|
|
37
|
+
|
|
38
|
+
@texture = Texture.new(
|
|
39
|
+
mag_filter: mag_filter,
|
|
40
|
+
min_filter: min_filter,
|
|
41
|
+
wrap_s: wrap_s,
|
|
42
|
+
wrap_t: wrap_t,
|
|
43
|
+
format: format,
|
|
44
|
+
type: type,
|
|
45
|
+
anisotropy: anisotropy
|
|
46
|
+
)
|
|
47
|
+
@texture.generate_mipmaps = generate_mipmaps
|
|
48
|
+
@texture.encoding = encoding
|
|
49
|
+
|
|
50
|
+
@depth_buffer = depth_buffer
|
|
51
|
+
@stencil_buffer = stencil_buffer
|
|
52
|
+
@depth_texture = depth_texture
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def set_size(width, height, depth = 1)
|
|
56
|
+
return if @width == width && @height == height && @depth == depth
|
|
57
|
+
|
|
58
|
+
@width = width
|
|
59
|
+
@height = height
|
|
60
|
+
@depth = depth
|
|
61
|
+
|
|
62
|
+
@texture.needs_update = true
|
|
63
|
+
|
|
64
|
+
dispose
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def clone
|
|
68
|
+
self.class.new.copy(self)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def copy(source)
|
|
72
|
+
@width = source.width
|
|
73
|
+
@height = source.height
|
|
74
|
+
@depth = source.depth
|
|
75
|
+
|
|
76
|
+
@viewport.copy(source.viewport)
|
|
77
|
+
|
|
78
|
+
@texture = source.texture.clone
|
|
79
|
+
|
|
80
|
+
@depth_buffer = source.depth_buffer
|
|
81
|
+
@stencil_buffer = source.stencil_buffer
|
|
82
|
+
@depth_texture = source.depth_texture&.clone
|
|
83
|
+
|
|
84
|
+
self
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def dispose
|
|
88
|
+
@texture.version += 1
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class WebGLRenderTarget < RenderTarget
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class WebGLMultipleRenderTargets < RenderTarget
|
|
96
|
+
attr_accessor :textures
|
|
97
|
+
|
|
98
|
+
def initialize(width: 1, height: 1, count: 1, **options)
|
|
99
|
+
super(width: width, height: height, **options)
|
|
100
|
+
|
|
101
|
+
@textures = Array.new(count) do
|
|
102
|
+
Texture.new(
|
|
103
|
+
mag_filter: options[:mag_filter] || :linear,
|
|
104
|
+
min_filter: options[:min_filter] || :linear,
|
|
105
|
+
wrap_s: options[:wrap_s] || :clamp_to_edge,
|
|
106
|
+
wrap_t: options[:wrap_t] || :clamp_to_edge,
|
|
107
|
+
format: options[:format] || :rgba,
|
|
108
|
+
type: options[:type] || :unsigned_byte
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def set_size(width, height, depth = 1)
|
|
114
|
+
return if @width == width && @height == height && @depth == depth
|
|
115
|
+
|
|
116
|
+
@width = width
|
|
117
|
+
@height = height
|
|
118
|
+
@depth = depth
|
|
119
|
+
|
|
120
|
+
@textures.each { |t| t.needs_update = true }
|
|
121
|
+
|
|
122
|
+
dispose
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sunrb
|
|
4
|
+
class Texture
|
|
5
|
+
MAPPING = {
|
|
6
|
+
uv: 300,
|
|
7
|
+
cube_reflection: 301,
|
|
8
|
+
cube_refraction: 302,
|
|
9
|
+
equirectangular_reflection: 303,
|
|
10
|
+
equirectangular_refraction: 304,
|
|
11
|
+
spherical_reflection: 305
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
WRAPPING = {
|
|
15
|
+
repeat: 1000,
|
|
16
|
+
clamp_to_edge: 1001,
|
|
17
|
+
mirrored_repeat: 1002
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
FILTER = {
|
|
21
|
+
nearest: 1003,
|
|
22
|
+
nearest_mipmap_nearest: 1004,
|
|
23
|
+
nearest_mipmap_linear: 1005,
|
|
24
|
+
linear: 1006,
|
|
25
|
+
linear_mipmap_nearest: 1007,
|
|
26
|
+
linear_mipmap_linear: 1008
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
FORMAT = {
|
|
30
|
+
alpha: 1021,
|
|
31
|
+
rgb: 1022,
|
|
32
|
+
rgba: 1023,
|
|
33
|
+
luminance: 1024,
|
|
34
|
+
luminance_alpha: 1025,
|
|
35
|
+
depth: 1026,
|
|
36
|
+
depth_stencil: 1027
|
|
37
|
+
}.freeze
|
|
38
|
+
|
|
39
|
+
TYPE = {
|
|
40
|
+
unsigned_byte: 1009,
|
|
41
|
+
byte: 1010,
|
|
42
|
+
short: 1011,
|
|
43
|
+
unsigned_short: 1012,
|
|
44
|
+
int: 1013,
|
|
45
|
+
unsigned_int: 1014,
|
|
46
|
+
float: 1015,
|
|
47
|
+
half_float: 1016
|
|
48
|
+
}.freeze
|
|
49
|
+
|
|
50
|
+
attr_accessor :uuid, :name, :image, :mipmaps
|
|
51
|
+
attr_accessor :mapping, :wrap_s, :wrap_t
|
|
52
|
+
attr_accessor :mag_filter, :min_filter
|
|
53
|
+
attr_accessor :anisotropy
|
|
54
|
+
attr_accessor :format, :internal_format, :type
|
|
55
|
+
attr_accessor :offset, :repeat, :center, :rotation
|
|
56
|
+
attr_accessor :matrix_auto_update, :matrix
|
|
57
|
+
attr_accessor :generate_mipmaps, :premultiply_alpha, :flip_y
|
|
58
|
+
attr_accessor :unpack_alignment, :encoding
|
|
59
|
+
attr_accessor :version, :needs_update
|
|
60
|
+
attr_accessor :user_data
|
|
61
|
+
|
|
62
|
+
def initialize(
|
|
63
|
+
image: nil,
|
|
64
|
+
mapping: :uv,
|
|
65
|
+
wrap_s: :clamp_to_edge,
|
|
66
|
+
wrap_t: :clamp_to_edge,
|
|
67
|
+
mag_filter: :linear,
|
|
68
|
+
min_filter: :linear_mipmap_linear,
|
|
69
|
+
format: :rgba,
|
|
70
|
+
type: :unsigned_byte,
|
|
71
|
+
anisotropy: 1
|
|
72
|
+
)
|
|
73
|
+
@uuid = SecureRandom.uuid
|
|
74
|
+
@name = ""
|
|
75
|
+
@image = image
|
|
76
|
+
@mipmaps = []
|
|
77
|
+
|
|
78
|
+
@mapping = mapping
|
|
79
|
+
@wrap_s = wrap_s
|
|
80
|
+
@wrap_t = wrap_t
|
|
81
|
+
|
|
82
|
+
@mag_filter = mag_filter
|
|
83
|
+
@min_filter = min_filter
|
|
84
|
+
|
|
85
|
+
@anisotropy = anisotropy
|
|
86
|
+
|
|
87
|
+
@format = format
|
|
88
|
+
@internal_format = nil
|
|
89
|
+
@type = type
|
|
90
|
+
|
|
91
|
+
@offset = Vector2.new(0, 0)
|
|
92
|
+
@repeat = Vector2.new(1, 1)
|
|
93
|
+
@center = Vector2.new(0, 0)
|
|
94
|
+
@rotation = 0
|
|
95
|
+
|
|
96
|
+
@matrix_auto_update = true
|
|
97
|
+
@matrix = Matrix3.new
|
|
98
|
+
|
|
99
|
+
@generate_mipmaps = true
|
|
100
|
+
@premultiply_alpha = false
|
|
101
|
+
@flip_y = true
|
|
102
|
+
@unpack_alignment = 4
|
|
103
|
+
|
|
104
|
+
@encoding = :linear
|
|
105
|
+
@version = 0
|
|
106
|
+
@needs_update = false
|
|
107
|
+
@user_data = {}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def needs_update=(value)
|
|
111
|
+
@version += 1 if value
|
|
112
|
+
@needs_update = value
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def update_matrix
|
|
116
|
+
@matrix.set_uv_transform(
|
|
117
|
+
@offset.x, @offset.y,
|
|
118
|
+
@repeat.x, @repeat.y,
|
|
119
|
+
@rotation,
|
|
120
|
+
@center.x, @center.y
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def clone
|
|
125
|
+
self.class.new.copy(self)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def copy(source)
|
|
129
|
+
@name = source.name
|
|
130
|
+
@image = source.image
|
|
131
|
+
@mipmaps = source.mipmaps.dup
|
|
132
|
+
|
|
133
|
+
@mapping = source.mapping
|
|
134
|
+
@wrap_s = source.wrap_s
|
|
135
|
+
@wrap_t = source.wrap_t
|
|
136
|
+
|
|
137
|
+
@mag_filter = source.mag_filter
|
|
138
|
+
@min_filter = source.min_filter
|
|
139
|
+
|
|
140
|
+
@anisotropy = source.anisotropy
|
|
141
|
+
|
|
142
|
+
@format = source.format
|
|
143
|
+
@internal_format = source.internal_format
|
|
144
|
+
@type = source.type
|
|
145
|
+
|
|
146
|
+
@offset.copy(source.offset)
|
|
147
|
+
@repeat.copy(source.repeat)
|
|
148
|
+
@center.copy(source.center)
|
|
149
|
+
@rotation = source.rotation
|
|
150
|
+
|
|
151
|
+
@matrix_auto_update = source.matrix_auto_update
|
|
152
|
+
@matrix.copy(source.matrix)
|
|
153
|
+
|
|
154
|
+
@generate_mipmaps = source.generate_mipmaps
|
|
155
|
+
@premultiply_alpha = source.premultiply_alpha
|
|
156
|
+
@flip_y = source.flip_y
|
|
157
|
+
@unpack_alignment = source.unpack_alignment
|
|
158
|
+
|
|
159
|
+
@encoding = source.encoding
|
|
160
|
+
@user_data = source.user_data.dup
|
|
161
|
+
|
|
162
|
+
self
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def dispose
|
|
166
|
+
@version += 1
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def to_h
|
|
170
|
+
{
|
|
171
|
+
uuid: @uuid,
|
|
172
|
+
name: @name,
|
|
173
|
+
mapping: @mapping,
|
|
174
|
+
wrap_s: @wrap_s,
|
|
175
|
+
wrap_t: @wrap_t,
|
|
176
|
+
mag_filter: @mag_filter,
|
|
177
|
+
min_filter: @min_filter,
|
|
178
|
+
anisotropy: @anisotropy,
|
|
179
|
+
format: @format,
|
|
180
|
+
type: @type,
|
|
181
|
+
offset: @offset.to_a,
|
|
182
|
+
repeat: @repeat.to_a,
|
|
183
|
+
center: @center.to_a,
|
|
184
|
+
rotation: @rotation,
|
|
185
|
+
flip_y: @flip_y,
|
|
186
|
+
encoding: @encoding
|
|
187
|
+
}
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
data/lib/3rb/version.rb
ADDED
data/lib/3rb.rb
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "3rb/version"
|
|
4
|
+
|
|
5
|
+
module Sunrb
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
class GLError < Error; end
|
|
8
|
+
class ShaderCompileError < Error; end
|
|
9
|
+
class TextureLoadError < Error; end
|
|
10
|
+
class ModelLoadError < Error; end
|
|
11
|
+
class InvalidArgumentError < Error; end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
require_relative "3rb/math/math_utils"
|
|
15
|
+
require_relative "3rb/math/vector2"
|
|
16
|
+
require_relative "3rb/math/vector3"
|
|
17
|
+
require_relative "3rb/math/vector4"
|
|
18
|
+
require_relative "3rb/math/matrix3"
|
|
19
|
+
require_relative "3rb/math/matrix4"
|
|
20
|
+
require_relative "3rb/math/quaternion"
|
|
21
|
+
require_relative "3rb/math/euler"
|
|
22
|
+
require_relative "3rb/math/color"
|
|
23
|
+
|
|
24
|
+
require_relative "3rb/core/buffer_attribute"
|
|
25
|
+
require_relative "3rb/core/object3d"
|
|
26
|
+
require_relative "3rb/core/scene"
|
|
27
|
+
require_relative "3rb/core/group"
|
|
28
|
+
|
|
29
|
+
require_relative "3rb/geometries/buffer_geometry"
|
|
30
|
+
require_relative "3rb/geometries/box_geometry"
|
|
31
|
+
require_relative "3rb/geometries/sphere_geometry"
|
|
32
|
+
require_relative "3rb/geometries/plane_geometry"
|
|
33
|
+
require_relative "3rb/geometries/cylinder_geometry"
|
|
34
|
+
require_relative "3rb/geometries/cone_geometry"
|
|
35
|
+
require_relative "3rb/geometries/torus_geometry"
|
|
36
|
+
|
|
37
|
+
require_relative "3rb/materials/material"
|
|
38
|
+
require_relative "3rb/materials/basic_material"
|
|
39
|
+
require_relative "3rb/materials/lambert_material"
|
|
40
|
+
require_relative "3rb/materials/phong_material"
|
|
41
|
+
require_relative "3rb/materials/standard_material"
|
|
42
|
+
require_relative "3rb/materials/shader_material"
|
|
43
|
+
|
|
44
|
+
require_relative "3rb/objects/mesh"
|
|
45
|
+
require_relative "3rb/objects/line"
|
|
46
|
+
require_relative "3rb/objects/points"
|
|
47
|
+
|
|
48
|
+
require_relative "3rb/cameras/camera"
|
|
49
|
+
require_relative "3rb/cameras/perspective_camera"
|
|
50
|
+
require_relative "3rb/cameras/orthographic_camera"
|
|
51
|
+
|
|
52
|
+
require_relative "3rb/lights/light"
|
|
53
|
+
require_relative "3rb/lights/ambient_light"
|
|
54
|
+
require_relative "3rb/lights/directional_light"
|
|
55
|
+
require_relative "3rb/lights/point_light"
|
|
56
|
+
require_relative "3rb/lights/spot_light"
|
|
57
|
+
require_relative "3rb/lights/hemisphere_light"
|
|
58
|
+
require_relative "3rb/lights/rect_area_light"
|
|
59
|
+
|
|
60
|
+
require_relative "3rb/renderers/renderer"
|
|
61
|
+
require_relative "3rb/renderers/opengl_renderer"
|
|
62
|
+
require_relative "3rb/renderers/shader_lib"
|
|
63
|
+
|
|
64
|
+
require_relative "3rb/dsl/helpers"
|
|
65
|
+
require_relative "3rb/dsl/scene_builder"
|
|
66
|
+
|
|
67
|
+
require_relative "3rb/textures/texture"
|
|
68
|
+
require_relative "3rb/textures/data_texture"
|
|
69
|
+
require_relative "3rb/textures/cube_texture"
|
|
70
|
+
require_relative "3rb/textures/render_target"
|
|
71
|
+
|
|
72
|
+
require_relative "3rb/loaders/loader"
|
|
73
|
+
require_relative "3rb/loaders/texture_loader"
|
|
74
|
+
require_relative "3rb/loaders/obj_loader"
|
|
75
|
+
require_relative "3rb/loaders/gltf_loader"
|
|
76
|
+
|
|
77
|
+
require_relative "3rb/controls/orbit_controls"
|
|
78
|
+
|
|
79
|
+
require_relative "3rb/animation/animation_clip"
|
|
80
|
+
require_relative "3rb/animation/animation_mixer"
|
|
81
|
+
|
|
82
|
+
begin
|
|
83
|
+
require_relative "3rb/native"
|
|
84
|
+
rescue LoadError => e
|
|
85
|
+
warn "Failed to load native FFI bindings: #{e.message}"
|
|
86
|
+
end
|
data/shaders/basic.frag
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#version 330 core
|
|
2
|
+
|
|
3
|
+
in vec2 vUv;
|
|
4
|
+
out vec4 FragColor;
|
|
5
|
+
|
|
6
|
+
uniform vec3 diffuse;
|
|
7
|
+
uniform float opacity;
|
|
8
|
+
uniform bool useMap;
|
|
9
|
+
uniform sampler2D map;
|
|
10
|
+
|
|
11
|
+
void main() {
|
|
12
|
+
vec4 diffuseColor = vec4(diffuse, opacity);
|
|
13
|
+
|
|
14
|
+
if (useMap) {
|
|
15
|
+
diffuseColor *= texture(map, vUv);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
FragColor = diffuseColor;
|
|
19
|
+
}
|
data/shaders/basic.vert
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#version 330 core
|
|
2
|
+
|
|
3
|
+
layout (location = 0) in vec3 position;
|
|
4
|
+
layout (location = 1) in vec3 normal;
|
|
5
|
+
layout (location = 2) in vec2 uv;
|
|
6
|
+
|
|
7
|
+
uniform mat4 modelViewMatrix;
|
|
8
|
+
uniform mat4 projectionMatrix;
|
|
9
|
+
|
|
10
|
+
out vec2 vUv;
|
|
11
|
+
|
|
12
|
+
void main() {
|
|
13
|
+
vUv = uv;
|
|
14
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Light structures and uniforms
|
|
2
|
+
|
|
3
|
+
struct AmbientLight {
|
|
4
|
+
vec3 color;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
struct DirectionalLight {
|
|
8
|
+
vec3 direction;
|
|
9
|
+
vec3 color;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
struct PointLight {
|
|
13
|
+
vec3 position;
|
|
14
|
+
vec3 color;
|
|
15
|
+
float distance;
|
|
16
|
+
float decay;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
struct SpotLight {
|
|
20
|
+
vec3 position;
|
|
21
|
+
vec3 direction;
|
|
22
|
+
vec3 color;
|
|
23
|
+
float distance;
|
|
24
|
+
float decay;
|
|
25
|
+
float coneCos;
|
|
26
|
+
float penumbraCos;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
#define MAX_LIGHTS 4
|
|
30
|
+
|
|
31
|
+
uniform AmbientLight ambientLights[MAX_LIGHTS];
|
|
32
|
+
uniform int numAmbientLights;
|
|
33
|
+
|
|
34
|
+
uniform DirectionalLight directionalLights[MAX_LIGHTS];
|
|
35
|
+
uniform int numDirectionalLights;
|
|
36
|
+
|
|
37
|
+
uniform PointLight pointLights[MAX_LIGHTS];
|
|
38
|
+
uniform int numPointLights;
|
|
39
|
+
|
|
40
|
+
uniform SpotLight spotLights[MAX_LIGHTS];
|
|
41
|
+
uniform int numSpotLights;
|
|
42
|
+
|
|
43
|
+
// Light calculation functions
|
|
44
|
+
float getDistanceAttenuation(float lightDistance, float cutoffDistance, float decayExponent) {
|
|
45
|
+
if (cutoffDistance > 0.0 && decayExponent > 0.0) {
|
|
46
|
+
return pow(clamp(1.0 - pow(lightDistance / cutoffDistance, 4.0), 0.0, 1.0), decayExponent);
|
|
47
|
+
}
|
|
48
|
+
return 1.0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
float getSpotAttenuation(float coneCosine, float penumbraCosine, float angleCosine) {
|
|
52
|
+
return smoothstep(coneCosine, penumbraCosine, angleCosine);
|
|
53
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#version 330 core
|
|
2
|
+
|
|
3
|
+
in vec3 vNormal;
|
|
4
|
+
in vec3 vWorldPosition;
|
|
5
|
+
in vec2 vUv;
|
|
6
|
+
|
|
7
|
+
out vec4 FragColor;
|
|
8
|
+
|
|
9
|
+
uniform vec3 diffuse;
|
|
10
|
+
uniform vec3 emissive;
|
|
11
|
+
uniform float opacity;
|
|
12
|
+
uniform bool useMap;
|
|
13
|
+
uniform sampler2D map;
|
|
14
|
+
|
|
15
|
+
uniform vec3 ambientLightColor;
|
|
16
|
+
uniform vec3 directionalLightDirection;
|
|
17
|
+
uniform vec3 directionalLightColor;
|
|
18
|
+
|
|
19
|
+
void main() {
|
|
20
|
+
vec3 normal = normalize(vNormal);
|
|
21
|
+
|
|
22
|
+
vec4 diffuseColor = vec4(diffuse, opacity);
|
|
23
|
+
if (useMap) {
|
|
24
|
+
diffuseColor *= texture(map, vUv);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Ambient
|
|
28
|
+
vec3 lighting = ambientLightColor;
|
|
29
|
+
|
|
30
|
+
// Directional light (Lambertian)
|
|
31
|
+
float dotNL = max(dot(normal, directionalLightDirection), 0.0);
|
|
32
|
+
lighting += directionalLightColor * dotNL;
|
|
33
|
+
|
|
34
|
+
vec3 outgoingLight = diffuseColor.rgb * lighting + emissive;
|
|
35
|
+
|
|
36
|
+
FragColor = vec4(outgoingLight, diffuseColor.a);
|
|
37
|
+
}
|