mittsu-opengl 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +18 -0
- data/.github/workflows/build-workflow.yml +67 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +1158 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +195 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/install-glfw.ps1 +13 -0
- data/lib/mittsu/generic_lib.rb +116 -0
- data/lib/mittsu/glfw/lib.rb +58 -0
- data/lib/mittsu/glfw/window.rb +231 -0
- data/lib/mittsu/opengl/buffer.rb +13 -0
- data/lib/mittsu/opengl/default_target.rb +50 -0
- data/lib/mittsu/opengl/geometry_group.rb +758 -0
- data/lib/mittsu/opengl/geometry_like.rb +132 -0
- data/lib/mittsu/opengl/gl_debug.rb +85 -0
- data/lib/mittsu/opengl/gl_extensions.rb +42 -0
- data/lib/mittsu/opengl/gl_mittsu_params.rb +53 -0
- data/lib/mittsu/opengl/helper.rb +120 -0
- data/lib/mittsu/opengl/implementation.rb +31 -0
- data/lib/mittsu/opengl/lib.rb +19 -0
- data/lib/mittsu/opengl/light_renderer.rb +43 -0
- data/lib/mittsu/opengl/material_basics.rb +57 -0
- data/lib/mittsu/opengl/plugins/shadow_map_plugin.rb +416 -0
- data/lib/mittsu/opengl/plugins/sprite_fragment.glsl +38 -0
- data/lib/mittsu/opengl/plugins/sprite_plugin.rb +250 -0
- data/lib/mittsu/opengl/plugins/sprite_vertex.glsl +31 -0
- data/lib/mittsu/opengl/program.rb +250 -0
- data/lib/mittsu/opengl/renderer.rb +1028 -0
- data/lib/mittsu/opengl/shader/chunk.rb +11 -0
- data/lib/mittsu/opengl/shader/chunks/alphamap_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/alphamap_pars_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/alphatest_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/bumpmap_pars_fragment.glsl +40 -0
- data/lib/mittsu/opengl/shader/chunks/color_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/color_pars_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/color_pars_vertex.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/color_vertex.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/common.glsl +60 -0
- data/lib/mittsu/opengl/shader/chunks/default_vertex.glsl +15 -0
- data/lib/mittsu/opengl/shader/chunks/defaultnormal_vertex.glsl +21 -0
- data/lib/mittsu/opengl/shader/chunks/envmap_fragment.glsl +62 -0
- data/lib/mittsu/opengl/shader/chunks/envmap_pars_fragment.glsl +21 -0
- data/lib/mittsu/opengl/shader/chunks/envmap_pars_vertex.glsl +7 -0
- data/lib/mittsu/opengl/shader/chunks/envmap_vertex.glsl +17 -0
- data/lib/mittsu/opengl/shader/chunks/fog_fragment.glsl +26 -0
- data/lib/mittsu/opengl/shader/chunks/fog_pars_fragment.glsl +15 -0
- data/lib/mittsu/opengl/shader/chunks/lightmap_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/lightmap_pars_fragment.glsl +6 -0
- data/lib/mittsu/opengl/shader/chunks/lightmap_pars_vertex.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/lightmap_vertex.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/lights_lambert_pars_vertex.glsl +43 -0
- data/lib/mittsu/opengl/shader/chunks/lights_lambert_vertex.glsl +196 -0
- data/lib/mittsu/opengl/shader/chunks/lights_phong_fragment.glsl +243 -0
- data/lib/mittsu/opengl/shader/chunks/lights_phong_pars_fragment.glsl +58 -0
- data/lib/mittsu/opengl/shader/chunks/lights_phong_pars_vertex.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/lights_phong_vertex.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/linear_to_gamma_fragment.glsl +2 -0
- data/lib/mittsu/opengl/shader/chunks/logdepthbuf_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/logdepthbuf_pars_fragment.glsl +12 -0
- data/lib/mittsu/opengl/shader/chunks/logdepthbuf_pars_vertex.glsl +11 -0
- data/lib/mittsu/opengl/shader/chunks/logdepthbuf_vertex.glsl +15 -0
- data/lib/mittsu/opengl/shader/chunks/map_fragment.glsl +9 -0
- data/lib/mittsu/opengl/shader/chunks/map_pars_fragment.glsl +11 -0
- data/lib/mittsu/opengl/shader/chunks/map_pars_vertex.glsl +6 -0
- data/lib/mittsu/opengl/shader/chunks/map_particle_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/map_particle_pars_fragment.glsl +6 -0
- data/lib/mittsu/opengl/shader/chunks/map_vertex.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/morphnormal_vertex.glsl +12 -0
- data/lib/mittsu/opengl/shader/chunks/morphtarget_pars_vertex.glsl +13 -0
- data/lib/mittsu/opengl/shader/chunks/morphtarget_vertex.glsl +20 -0
- data/lib/mittsu/opengl/shader/chunks/normalmap_pars_fragment.glsl +27 -0
- data/lib/mittsu/opengl/shader/chunks/shadowmap_fragment.glsl +216 -0
- data/lib/mittsu/opengl/shader/chunks/shadowmap_pars_fragment.glsl +19 -0
- data/lib/mittsu/opengl/shader/chunks/shadowmap_pars_vertex.glsl +6 -0
- data/lib/mittsu/opengl/shader/chunks/shadowmap_vertex.glsl +9 -0
- data/lib/mittsu/opengl/shader/chunks/skinbase_vertex.glsl +8 -0
- data/lib/mittsu/opengl/shader/chunks/skinning_pars_vertex.glsl +47 -0
- data/lib/mittsu/opengl/shader/chunks/skinning_vertex.glsl +20 -0
- data/lib/mittsu/opengl/shader/chunks/skinnormal_vertex.glsl +20 -0
- data/lib/mittsu/opengl/shader/chunks/specularmap_fragment.glsl +12 -0
- data/lib/mittsu/opengl/shader/chunks/specularmap_pars_fragment.glsl +5 -0
- data/lib/mittsu/opengl/shader/chunks/worldpos_vertex.glsl +17 -0
- data/lib/mittsu/opengl/shader/lib/basic/basic_fragment.rbsl +37 -0
- data/lib/mittsu/opengl/shader/lib/basic/basic_uniforms.rbslu +3 -0
- data/lib/mittsu/opengl/shader/lib/basic/basic_vertex.rbsl +33 -0
- data/lib/mittsu/opengl/shader/lib/cube/cube_fragment.rbsl +12 -0
- data/lib/mittsu/opengl/shader/lib/cube/cube_uniforms.rbslu +2 -0
- data/lib/mittsu/opengl/shader/lib/cube/cube_vertex.rbsl +12 -0
- data/lib/mittsu/opengl/shader/lib/depth_rgba/depth_rgba_fragment.rbsl +26 -0
- data/lib/mittsu/opengl/shader/lib/depth_rgba/depth_rgba_uniforms.rbslu +0 -0
- data/lib/mittsu/opengl/shader/lib/depth_rgba/depth_rgba_vertex.rbsl +12 -0
- data/lib/mittsu/opengl/shader/lib/lambert/lambert_fragment.rbsl +56 -0
- data/lib/mittsu/opengl/shader/lib/lambert/lambert_uniforms.rbslu +7 -0
- data/lib/mittsu/opengl/shader/lib/lambert/lambert_vertex.rbsl +37 -0
- data/lib/mittsu/opengl/shader/lib/particle_basic/particle_basic_fragment.rbsl +27 -0
- data/lib/mittsu/opengl/shader/lib/particle_basic/particle_basic_uniforms.rbslu +2 -0
- data/lib/mittsu/opengl/shader/lib/particle_basic/particle_basic_vertex.rbsl +25 -0
- data/lib/mittsu/opengl/shader/lib/phong/phong_fragment.rbsl +45 -0
- data/lib/mittsu/opengl/shader/lib/phong/phong_uniforms.rbslu +11 -0
- data/lib/mittsu/opengl/shader/lib/phong/phong_vertex.rbsl +43 -0
- data/lib/mittsu/opengl/shader/lib.rb +45 -0
- data/lib/mittsu/opengl/shader/rbsl_loader.rb +168 -0
- data/lib/mittsu/opengl/shader/templates/fragment.glsl.erb +105 -0
- data/lib/mittsu/opengl/shader/templates/vertex.glsl.erb +143 -0
- data/lib/mittsu/opengl/shader/uniforms_lib.rb +86 -0
- data/lib/mittsu/opengl/shader/uniforms_utils.rb +31 -0
- data/lib/mittsu/opengl/shader.rb +56 -0
- data/lib/mittsu/opengl/state.rb +205 -0
- data/lib/mittsu/opengl/version.rb +5 -0
- data/lib/mittsu/opengl.rb +2 -0
- data/lib/mittsu/opengl_implementation/core/buffer_geometry.rb +11 -0
- data/lib/mittsu/opengl_implementation/core/geometry.rb +346 -0
- data/lib/mittsu/opengl_implementation/core/object_3d.rb +134 -0
- data/lib/mittsu/opengl_implementation/lights/ambient_light.rb +26 -0
- data/lib/mittsu/opengl_implementation/lights/directional_light.rb +35 -0
- data/lib/mittsu/opengl_implementation/lights/hemisphere_light.rb +39 -0
- data/lib/mittsu/opengl_implementation/lights/light.rb +55 -0
- data/lib/mittsu/opengl_implementation/lights/point_light.rb +36 -0
- data/lib/mittsu/opengl_implementation/lights/spot_light.rb +47 -0
- data/lib/mittsu/opengl_implementation/materials/line_basic_material.rb +16 -0
- data/lib/mittsu/opengl_implementation/materials/material.rb +274 -0
- data/lib/mittsu/opengl_implementation/materials/mesh_basic_material.rb +21 -0
- data/lib/mittsu/opengl_implementation/materials/mesh_lambert_material.rb +33 -0
- data/lib/mittsu/opengl_implementation/materials/mesh_phong_material.rb +44 -0
- data/lib/mittsu/opengl_implementation/materials/point_cloud_material.rb +27 -0
- data/lib/mittsu/opengl_implementation/materials/shader_material.rb +11 -0
- data/lib/mittsu/opengl_implementation/objects/group.rb +9 -0
- data/lib/mittsu/opengl_implementation/objects/line.rb +45 -0
- data/lib/mittsu/opengl_implementation/objects/mesh.rb +70 -0
- data/lib/mittsu/opengl_implementation/objects/point_cloud.rb +39 -0
- data/lib/mittsu/opengl_implementation/objects/sprite.rb +12 -0
- data/lib/mittsu/opengl_implementation/scenes/scene.rb +9 -0
- data/lib/mittsu/opengl_implementation/textures/compressed_texture.rb +20 -0
- data/lib/mittsu/opengl_implementation/textures/cube_texture.rb +77 -0
- data/lib/mittsu/opengl_implementation/textures/data_texture.rb +21 -0
- data/lib/mittsu/opengl_implementation/textures/render_target.rb +124 -0
- data/lib/mittsu/opengl_implementation/textures/texture.rb +107 -0
- data/mittsu-opengl.gemspec +36 -0
- metadata +314 -0
@@ -0,0 +1,416 @@
|
|
1
|
+
require 'mittsu/math'
|
2
|
+
|
3
|
+
module Mittsu
|
4
|
+
class ShadowMapPlugin
|
5
|
+
def initialize(renderer, lights, opengl_objects, opengl_objects_immediate)
|
6
|
+
@renderer, @lights = renderer, lights
|
7
|
+
@opengl_objects = opengl_objects
|
8
|
+
@opengl_objects_immediate = opengl_objects_immediate
|
9
|
+
|
10
|
+
@frustum = Frustum.new
|
11
|
+
@proj_screen_matrix = Matrix4.new
|
12
|
+
|
13
|
+
@min = Vector3.new
|
14
|
+
@max = Vector3.new
|
15
|
+
|
16
|
+
@matrix_position = Vector3.new
|
17
|
+
|
18
|
+
@render_list = []
|
19
|
+
|
20
|
+
depth_shader = OpenGL::Shader::Lib[:depth_rgba]
|
21
|
+
depth_uniforms = OpenGL::Shader::UniformsUtils.clone(depth_shader.uniforms)
|
22
|
+
|
23
|
+
@depth_material = ShaderMaterial.new(
|
24
|
+
uniforms: depth_uniforms,
|
25
|
+
vertex_shader: depth_shader.vertex_shader,
|
26
|
+
fragment_shader: depth_shader.fragment_shader
|
27
|
+
)
|
28
|
+
|
29
|
+
@depth_material_morph = ShaderMaterial.new(
|
30
|
+
uniforms: depth_uniforms,
|
31
|
+
vertex_shader: depth_shader.vertex_shader,
|
32
|
+
fragment_shader: depth_shader.fragment_shader,
|
33
|
+
morph_targets: true
|
34
|
+
)
|
35
|
+
|
36
|
+
@depth_material_skin = ShaderMaterial.new(
|
37
|
+
uniforms: depth_uniforms,
|
38
|
+
vertex_shader: depth_shader.vertex_shader,
|
39
|
+
fragment_shader: depth_shader.fragment_shader,
|
40
|
+
skinning: true
|
41
|
+
)
|
42
|
+
|
43
|
+
@depth_material_morph_skin = ShaderMaterial.new(
|
44
|
+
uniforms: depth_uniforms,
|
45
|
+
vertex_shader: depth_shader.vertex_shader,
|
46
|
+
fragment_shader: depth_shader.fragment_shader,
|
47
|
+
morph_targets: true,
|
48
|
+
skinning: true
|
49
|
+
)
|
50
|
+
|
51
|
+
@depth_material.shadow_pass = true
|
52
|
+
@depth_material_morph.shadow_pass = true
|
53
|
+
@depth_material_skin.shadow_pass = true
|
54
|
+
@depth_material_morph_skin.shadow_pass = true
|
55
|
+
end
|
56
|
+
|
57
|
+
def render(scene, camera)
|
58
|
+
return unless @renderer.shadow_map_enabled
|
59
|
+
|
60
|
+
lights = []
|
61
|
+
fog = nil
|
62
|
+
|
63
|
+
# set GL state for depth map
|
64
|
+
|
65
|
+
GL.ClearColor(1.0, 1.0, 1.0, 1.0)
|
66
|
+
GL.Disable(GL::BLEND)
|
67
|
+
|
68
|
+
GL.Enable(GL::CULL_FACE)
|
69
|
+
GL.FrontFace(GL::CCW)
|
70
|
+
|
71
|
+
if @renderer.shadow_map_cull_face = CullFaceFront
|
72
|
+
GL.CullFace(GL::FRONT)
|
73
|
+
else
|
74
|
+
GL.CullFace(GL::BACK)
|
75
|
+
end
|
76
|
+
|
77
|
+
@renderer.state.set_depth_test(true)
|
78
|
+
|
79
|
+
# process lights
|
80
|
+
# - skip lights that are not casting shadows
|
81
|
+
# - create virtual lights for cascaded shadow maps
|
82
|
+
|
83
|
+
@lights.select(&:cast_shadow).each do |light|
|
84
|
+
if light.is_a?(DirectionalLight) && light.shadow_cascade
|
85
|
+
light.shadow_cascade_count.times do |n|
|
86
|
+
if !light.shadow_cascade_array[n]
|
87
|
+
virtual_light = create_virtual_light(light, n)
|
88
|
+
virtual_light.original_camera = camera
|
89
|
+
|
90
|
+
gyro = Gyroscope.new
|
91
|
+
gyro.position.copy(light.shadow_cascade_offset)
|
92
|
+
|
93
|
+
gyro.add(virtual_light)
|
94
|
+
gyro.add(virtual_light.target)
|
95
|
+
|
96
|
+
camera.add(gyro)
|
97
|
+
|
98
|
+
light.shadow_cascade_array[n] = virtual_light
|
99
|
+
else
|
100
|
+
virtual_light = light.shadow_cascade_array[n]
|
101
|
+
end
|
102
|
+
|
103
|
+
update_virtual_light(light, n)
|
104
|
+
|
105
|
+
lights << virtual_light
|
106
|
+
end
|
107
|
+
else
|
108
|
+
lights << light
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# render depth map
|
113
|
+
|
114
|
+
lights.each do |light|
|
115
|
+
if !light.shadow_map
|
116
|
+
shadow_filter = LinearFilter
|
117
|
+
if @renderer.shadow_map_type == PCFSoftShadowMap
|
118
|
+
shadow_filter = NearestFilter
|
119
|
+
end
|
120
|
+
|
121
|
+
pars = { min_filter: shadow_filter, mag_filter: shadow_filter, format: RGBAFormat }
|
122
|
+
|
123
|
+
light.shadow_map = RenderTarget.new(light.shadow_map_width, light.shadow_map_height, pars)
|
124
|
+
light.shadow_map.renderer = @renderer
|
125
|
+
light.shadow_map_size = Vector2.new(light.shadow_map_width, light.shadow_map_height)
|
126
|
+
|
127
|
+
light.shadow_matrix = Matrix4.new
|
128
|
+
end
|
129
|
+
|
130
|
+
if !light.shadow_camera
|
131
|
+
case light
|
132
|
+
when SpotLight
|
133
|
+
light.shadow_camera = PerspectiveCamera.new(light.shadow_camera_fov, light.shadow_map_width / light.shadow_map_height, light.shadow_camera_near, light.shadow_camera_far)
|
134
|
+
when DirectionalLight
|
135
|
+
light.shadow_camera = OrthographicCamera.new(light.shadow_camera_left, light.shadow_camera_right, light.shadow_camera_top, light.shadow_camera_bottom, light.shadow_camera_near, light.shadow_camera_far)
|
136
|
+
else
|
137
|
+
puts "ERROR: Mittsu::ShadowMapPlugin: Unsupported light type for shadow #{light.inspect}"
|
138
|
+
next
|
139
|
+
end
|
140
|
+
|
141
|
+
scene.add(light.shadow_camera)
|
142
|
+
scene.update_matrix_world if scene.auto_update
|
143
|
+
end
|
144
|
+
|
145
|
+
if light.shadow_camera_visible && !light.camera_helper
|
146
|
+
light.camera_helper = CameraHelper.new(light.shadow_camera)
|
147
|
+
scene.add(light.camera_helper)
|
148
|
+
end
|
149
|
+
|
150
|
+
if light.virtual? && virtual_light.original_camera == camera
|
151
|
+
update_shadow_camera(camera, light)
|
152
|
+
end
|
153
|
+
|
154
|
+
shadow_map = light.shadow_map
|
155
|
+
shadow_matrix = light.shadow_matrix
|
156
|
+
shadow_camera = light.shadow_camera
|
157
|
+
|
158
|
+
#
|
159
|
+
|
160
|
+
shadow_camera.position.set_from_matrix_position(light.matrix_world)
|
161
|
+
@matrix_position.set_from_matrix_position(light.target.matrix_world)
|
162
|
+
shadow_camera.look_at(@matrix_position)
|
163
|
+
shadow_camera.update_matrix_world
|
164
|
+
|
165
|
+
shadow_camera.matrix_world_inverse.inverse(shadow_camera.matrix_world)
|
166
|
+
|
167
|
+
#
|
168
|
+
|
169
|
+
|
170
|
+
light.camera_helper.visible = light.shadow_camera_visible if light.camera_helper
|
171
|
+
light.camera_helper.update_points if light.shadow_camera_visible
|
172
|
+
|
173
|
+
# compute shadow matrix
|
174
|
+
|
175
|
+
shadow_matrix.set(
|
176
|
+
0.5, 0.0, 0.0, 0.5,
|
177
|
+
0.0, 0.5, 0.0, 0.5,
|
178
|
+
0.0, 0.0, 0.5, 0.5,
|
179
|
+
0.0, 0.0, 0.0, 1.0
|
180
|
+
)
|
181
|
+
|
182
|
+
shadow_matrix.multiply(shadow_camera.projection_matrix)
|
183
|
+
shadow_matrix.multiply(shadow_camera.matrix_world_inverse)
|
184
|
+
|
185
|
+
# update camera matrices and frustum
|
186
|
+
|
187
|
+
@proj_screen_matrix.multiply_matrices(shadow_camera.projection_matrix, shadow_camera.matrix_world_inverse)
|
188
|
+
@frustum.set_from_matrix(@proj_screen_matrix)
|
189
|
+
|
190
|
+
# render shadow map
|
191
|
+
|
192
|
+
@renderer.set_render_target(shadow_map)
|
193
|
+
@renderer.clear
|
194
|
+
|
195
|
+
# set object matrices & frustum culling
|
196
|
+
|
197
|
+
@render_list.clear
|
198
|
+
|
199
|
+
project_object(scene, scene, shadow_camera)
|
200
|
+
|
201
|
+
# render regular obejcts
|
202
|
+
|
203
|
+
@render_list.each do |opengl_object|
|
204
|
+
object = opengl_object[:object]
|
205
|
+
buffer = opengl_object[:buffer]
|
206
|
+
|
207
|
+
# culling is overridden globally for all objects
|
208
|
+
# while rendering depth map
|
209
|
+
|
210
|
+
# need to deal with MeshFaceMaterial somehow
|
211
|
+
# in that case just use the first of material.materials for now
|
212
|
+
# (proper solution would require to break objects by materials
|
213
|
+
# similarly to regular rendering and then set corresponding
|
214
|
+
# depth materials per each chunk instead of just once per object)
|
215
|
+
|
216
|
+
object_material = get_object_material(object)
|
217
|
+
|
218
|
+
# TODO: SkinnedMesh/morph_targets
|
219
|
+
# use_morphing = !object.geometry.morph_targets.nil? && !object.geometry.morph_targets.empty?
|
220
|
+
# use_skinning = object.is_a?(SkinnedMesh) && object_material.skinning
|
221
|
+
|
222
|
+
# TODO: SkinnedMesh/morph_targets
|
223
|
+
# if object.custom_depth_material
|
224
|
+
# material = object.custom_depth_material
|
225
|
+
# elsif use_skinning
|
226
|
+
# material = use_morphing ? @depth_material_morph_skin : @depth_material_skin
|
227
|
+
# elsif use_morphing
|
228
|
+
# material = @deptth_material_morph
|
229
|
+
# else
|
230
|
+
material = @depth_material
|
231
|
+
# end
|
232
|
+
|
233
|
+
@renderer.set_material_faces(object_material)
|
234
|
+
|
235
|
+
if buffer.is_a?(BufferGeometry)
|
236
|
+
@renderer.render_buffer_direct(shadow_camera, @lights, fog, material, buffer, object)
|
237
|
+
else
|
238
|
+
@renderer.render_buffer(shadow_camera, @lights, fog, material, buffer, object)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# set materices and rendr immeidate objects
|
243
|
+
|
244
|
+
@opengl_objects_immediate.each do |opengl_object_immediate|
|
245
|
+
opengl_object = opengl_object_immediate
|
246
|
+
object = opengl_object[:object]
|
247
|
+
|
248
|
+
if object.visible && object.cast_shadow
|
249
|
+
object[:_model_view_matrix].multiply_matrices(shadow_camera.matrix_womatrix_world_inverse, object.matrix_world)
|
250
|
+
@renderer.render_immediate_object(shadow_camera, @lights, fog, @depth_material, object)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# restore GL state
|
256
|
+
|
257
|
+
clear_color = @renderer.get_clear_color
|
258
|
+
clear_alpha = @renderer.get_clear_alpha
|
259
|
+
|
260
|
+
GL.ClearColor(clear_color.r, clear_color.g, clear_color.b, clear_alpha)
|
261
|
+
GL.Enable(GL::BLEND)
|
262
|
+
|
263
|
+
if @renderer.shadow_map_cull_face == CullFaceFront
|
264
|
+
GL.CullFace(GL::BACK)
|
265
|
+
end
|
266
|
+
|
267
|
+
@renderer.reset_gl_state
|
268
|
+
end
|
269
|
+
|
270
|
+
def project_object(scene, object, shadow_camera)
|
271
|
+
if object.visible
|
272
|
+
opengl_objects = @opengl_objects[object.id]
|
273
|
+
|
274
|
+
if opengl_objects && object.cast_shadow && (object.frustum_culled == false || @frustum.intersects_object?(object) == true)
|
275
|
+
opengl_objects.each do |opengl_object|
|
276
|
+
object.model_view_matrix.multiply_matrices(shadow_camera.matrix_world_inverse, object.matrix_world)
|
277
|
+
@render_list << opengl_object
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
object.children.each do |child|
|
282
|
+
project_object(scene, child, shadow_camera)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def create_virtual_light(light, cascade)
|
288
|
+
DirectionalLight.new.tap do |virtual_light|
|
289
|
+
virtual_light.is_virtual = true
|
290
|
+
|
291
|
+
virtual_light.only_shadow = true
|
292
|
+
virtual_light.cast_shadow = true
|
293
|
+
|
294
|
+
virtual_light.shadow_camera_near = light.shadow_camera_near
|
295
|
+
virtual_light.shadow_camera_far = light.shadow_camera_far
|
296
|
+
|
297
|
+
virtual_light.shadow_camera_left = light.shadow_camera_left
|
298
|
+
virtual_light.shadow_camera_right = light.shadow_camera_right
|
299
|
+
virtual_light.shadow_camera_bottom = light.shadow_camera_bottom
|
300
|
+
virtual_light.shadow_camera_top = light.shadow_camera_top
|
301
|
+
|
302
|
+
virtual_light.shadow_camera_visible = light.shadow_camera_visible
|
303
|
+
|
304
|
+
virtual_light.shadow_darkness = light.shadow_darkness
|
305
|
+
|
306
|
+
virtual_light.shadow_darkness = light.shadow_darkness
|
307
|
+
|
308
|
+
virtual_light.shadow_bias = light.shadow_cascade_bias[cascade]
|
309
|
+
virtual_light.shadow_map_width = light.shadow_cascade_width[cascade]
|
310
|
+
virtual_light.shadow_map_height = light.shadow_cascade_height[cascade]
|
311
|
+
|
312
|
+
points_world = virtual_light.points_world = []
|
313
|
+
points_frustum = virtual_light.points_frustum = []
|
314
|
+
|
315
|
+
8.times do
|
316
|
+
points_world << Vector3.new
|
317
|
+
points_frustum << Vector3.new
|
318
|
+
end
|
319
|
+
|
320
|
+
near_z = light.shadow_cascade_near_z[cascade]
|
321
|
+
far_z = light.shadow_cascade_far_z[cascade]
|
322
|
+
|
323
|
+
points_frustum[0].set(-1.0, -1.0, near_z)
|
324
|
+
points_frustum[1].set( 1.0, -1.0, near_z)
|
325
|
+
points_frustum[2].set(-1.0, 1.0, near_z)
|
326
|
+
points_frustum[3].set( 1.0, 1.0, near_z)
|
327
|
+
|
328
|
+
points_frustum[4].set(-1.0, -1.0, far_z)
|
329
|
+
points_frustum[5].set( 1.0, -1.0, far_z)
|
330
|
+
points_frustum[6].set(-1.0, 1.0, far_z)
|
331
|
+
points_frustum[7].set( 1.0, 1.0, far_z)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# synchronize virtual light with the original light
|
336
|
+
|
337
|
+
def update_virtual_light(light, cascade)
|
338
|
+
virtual_light = light.shadow_cascade_array[cascade]
|
339
|
+
|
340
|
+
virtual_light.position.copy(light.position)
|
341
|
+
virtual_light.target.position.copy(light.target.position)
|
342
|
+
virtual_light.look_at(virtual_light.target)
|
343
|
+
|
344
|
+
virtual_light.shadow_camera_visible = light.shadow_camera_visible
|
345
|
+
virtual_light.shadow_darkness = light.shadow_darkness
|
346
|
+
|
347
|
+
virtual_light.shadow_bias = light.shadow_cascade_bias[cascade]
|
348
|
+
|
349
|
+
near_z = light.shadow_cascade_near_z[cascade]
|
350
|
+
far_z = light.shadow_cascade_far_z[cascade]
|
351
|
+
|
352
|
+
points_frustum = virtual_light.points_frustum
|
353
|
+
|
354
|
+
points_frustum[0].z = near_z
|
355
|
+
points_frustum[1].z = near_z
|
356
|
+
points_frustum[2].z = near_z
|
357
|
+
points_frustum[3].z = near_z
|
358
|
+
|
359
|
+
points_frustum[4].z = far_z
|
360
|
+
points_frustum[5].z = far_z
|
361
|
+
points_frustum[6].z = far_z
|
362
|
+
points_frustum[7].z = far_z
|
363
|
+
end
|
364
|
+
|
365
|
+
# fit shadow camera's ortho frustum to camera frustum
|
366
|
+
|
367
|
+
def update_shadow_camera(camera, light)
|
368
|
+
shadow_camera = light.shadow_camera
|
369
|
+
points_frustum = light.pointa_frustum
|
370
|
+
points_world = light.points_world
|
371
|
+
|
372
|
+
@min.set(Float::INFINITY, Float::INFINITY, Float::INFINITY)
|
373
|
+
@max.set(-Float::INFINITY, -Float::INFINITY, -Float::INFINITY)
|
374
|
+
|
375
|
+
8.times do |i|
|
376
|
+
p = points_world[i]
|
377
|
+
|
378
|
+
p.copy(points_frustum[i])
|
379
|
+
p.unproject(camera)
|
380
|
+
|
381
|
+
p.apply_matrix4(shadow_camera.matrix_world_inverse)
|
382
|
+
|
383
|
+
@min.x = p.x if (p.x < @min.x)
|
384
|
+
@max.x = p.x if (p.x > @max.x)
|
385
|
+
|
386
|
+
@min.y = p.y if (p.y < @min.y)
|
387
|
+
@max.y = p.y if (p.y > @max.y)
|
388
|
+
|
389
|
+
@min.z = p.z if (p.z < @min.z)
|
390
|
+
@max.z = p.z if (p.z > @max.z)
|
391
|
+
end
|
392
|
+
|
393
|
+
shadow_camera.left = @min.x
|
394
|
+
shadow_camera.right = @max.x
|
395
|
+
shadow_camera.top = @max.y
|
396
|
+
shadow_camera.bottom = @min.y
|
397
|
+
|
398
|
+
# can't really fit near/far
|
399
|
+
# shadow_camera.near = @min.x
|
400
|
+
# shadow_camera.far = @max.z
|
401
|
+
|
402
|
+
shadow_camera.update_projection_matrix
|
403
|
+
end
|
404
|
+
|
405
|
+
# For the moment just ignore objects that have multiple materials with different animation methods
|
406
|
+
# Only the frst material will be taken into account for deciding which depth material to use for shadow maps
|
407
|
+
|
408
|
+
def get_object_material(object)
|
409
|
+
if object.material.is_a?(MeshFaceMaterial)
|
410
|
+
object.material.materials[0]
|
411
|
+
else
|
412
|
+
object.material
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#version 330
|
2
|
+
|
3
|
+
uniform vec3 color;
|
4
|
+
uniform sampler2D map;
|
5
|
+
uniform float opacity;
|
6
|
+
|
7
|
+
uniform int fogType;
|
8
|
+
uniform vec3 fogColor;
|
9
|
+
uniform float fogDensity;
|
10
|
+
uniform float fogNear;
|
11
|
+
uniform float fogFar;
|
12
|
+
uniform float alphaTest;
|
13
|
+
|
14
|
+
in vec2 vUV;
|
15
|
+
layout(location = 0) out vec4 fragColor;
|
16
|
+
|
17
|
+
void main() {
|
18
|
+
vec4 texture = texture( map, vUV );
|
19
|
+
|
20
|
+
if ( texture.a < alphaTest ) discard;
|
21
|
+
|
22
|
+
fragColor = vec4( color * texture.xyz, texture.a * opacity );
|
23
|
+
|
24
|
+
if ( fogType > 0 ) {
|
25
|
+
float depth = gl_FragCoord.z / gl_FragCoord.w;
|
26
|
+
float fogFactor = 0.0;
|
27
|
+
|
28
|
+
if ( fogType == 1 ) {
|
29
|
+
fogFactor = smoothstep( fogNear, fogFar, depth );
|
30
|
+
} else {
|
31
|
+
const float LOG2 = 1.442695;
|
32
|
+
float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );
|
33
|
+
fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );
|
34
|
+
}
|
35
|
+
|
36
|
+
fragColor = mix( fragColor, vec4( fogColor, fragColor.w ), fogFactor );
|
37
|
+
}
|
38
|
+
}
|
@@ -0,0 +1,250 @@
|
|
1
|
+
module Mittsu
|
2
|
+
class SpritePlugin
|
3
|
+
include OpenGL::Helper
|
4
|
+
|
5
|
+
VERTICES = [
|
6
|
+
-0.5, -0.5, 0.0, 0.0,
|
7
|
+
0.5, -0.5, 1.0, 0.0,
|
8
|
+
0.5, 0.5, 1.0, 1.0,
|
9
|
+
-0.5, 0.5, 0.0, 1.0
|
10
|
+
] # Float32Array
|
11
|
+
|
12
|
+
FACES = [
|
13
|
+
0, 1, 2,
|
14
|
+
0, 2, 3
|
15
|
+
] # Uint16Array
|
16
|
+
|
17
|
+
def initialize(renderer, sprites)
|
18
|
+
@renderer = renderer
|
19
|
+
@sprites = sprites
|
20
|
+
@program = nil
|
21
|
+
|
22
|
+
# for decomposing matrixWorld
|
23
|
+
@sprite_position = Vector3.new
|
24
|
+
@sprite_rotation = Quaternion.new
|
25
|
+
@sprite_scale = Vector3.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(scene, camera)
|
29
|
+
return if @sprites.empty?
|
30
|
+
|
31
|
+
init if @program.nil?
|
32
|
+
setup_gl_for_render(camera)
|
33
|
+
setup_fog(scene)
|
34
|
+
|
35
|
+
update_positions_and_sort(camera)
|
36
|
+
|
37
|
+
render_all_sprites(scene)
|
38
|
+
|
39
|
+
GL.Enable(GL::CULL_FACE)
|
40
|
+
@renderer.reset_gl_state
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def init
|
46
|
+
create_vertex_array_object
|
47
|
+
create_program
|
48
|
+
|
49
|
+
init_attributes
|
50
|
+
init_uniforms
|
51
|
+
|
52
|
+
# TODO: canvas texture??
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_vertex_array_object
|
56
|
+
@vertex_array_object = GL.CreateVertexArray
|
57
|
+
GL.BindVertexArray(@vertex_array_object)
|
58
|
+
|
59
|
+
@vertex_buffer = GL.CreateBuffer
|
60
|
+
@element_buffer = GL.CreateBuffer
|
61
|
+
|
62
|
+
GL.BindBuffer(GL::ARRAY_BUFFER, @vertex_buffer)
|
63
|
+
GL.BufferData_easy(GL::ARRAY_BUFFER, VERTICES, GL::STATIC_DRAW)
|
64
|
+
|
65
|
+
GL.BindBuffer(GL::ELEMENT_ARRAY_BUFFER, @element_buffer)
|
66
|
+
GL.BufferData_easy(GL::ELEMENT_ARRAY_BUFFER, FACES, GL::STATIC_DRAW)
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_program
|
70
|
+
@program = GL.CreateProgram
|
71
|
+
|
72
|
+
vertex_shader = OpenGL::Shader.new(GL::VERTEX_SHADER, File.read(File.join(__dir__, 'sprite_vertex.glsl')))
|
73
|
+
fragment_shader = OpenGL::Shader.new(GL::FRAGMENT_SHADER, File.read(File.join(__dir__, 'sprite_fragment.glsl')))
|
74
|
+
|
75
|
+
GL.AttachShader(@program, vertex_shader.shader)
|
76
|
+
GL.AttachShader(@program, fragment_shader.shader)
|
77
|
+
|
78
|
+
GL.LinkProgram(@program)
|
79
|
+
end
|
80
|
+
|
81
|
+
def init_attributes
|
82
|
+
@attributes = {
|
83
|
+
position: GL.GetAttribLocation(@program, 'position'),
|
84
|
+
uv: GL.GetAttribLocation(@program, 'uv')
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def init_uniforms
|
89
|
+
@uniforms = {
|
90
|
+
uvOffset: GL.GetUniformLocation(@program, 'uvOffset'),
|
91
|
+
uvScale: GL.GetUniformLocation(@program, 'uvScale'),
|
92
|
+
|
93
|
+
rotation: GL.GetUniformLocation(@program, 'rotation'),
|
94
|
+
scale: GL.GetUniformLocation(@program, 'scale'),
|
95
|
+
|
96
|
+
color: GL.GetUniformLocation(@program, 'color'),
|
97
|
+
map: GL.GetUniformLocation(@program, 'map'),
|
98
|
+
opacity: GL.GetUniformLocation(@program, 'opacity'),
|
99
|
+
|
100
|
+
modelViewMatrix: GL.GetUniformLocation(@program, 'modelViewMatrix'),
|
101
|
+
projectionMatrix: GL.GetUniformLocation(@program, 'projectionMatrix'),
|
102
|
+
|
103
|
+
fogType: GL.GetUniformLocation(@program, 'fogType'),
|
104
|
+
fogDensity: GL.GetUniformLocation(@program, 'fogDensity'),
|
105
|
+
fogNear: GL.GetUniformLocation(@program, 'fogNear'),
|
106
|
+
fogFar: GL.GetUniformLocation(@program, 'fogFar'),
|
107
|
+
fogColor: GL.GetUniformLocation(@program, 'fogColor'),
|
108
|
+
|
109
|
+
alphaTest: GL.GetUniformLocation(@program, 'alphaTest')
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def painter_sort_stable(a, b)
|
114
|
+
if a.z != b.z
|
115
|
+
b.z - a.z
|
116
|
+
else
|
117
|
+
b.id - a.id
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def setup_gl_for_render(camera)
|
122
|
+
GL.UseProgram(@program)
|
123
|
+
|
124
|
+
GL.Disable(GL::CULL_FACE)
|
125
|
+
GL.Enable(GL::BLEND)
|
126
|
+
|
127
|
+
GL.BindVertexArray(@vertex_array_object)
|
128
|
+
|
129
|
+
GL.EnableVertexAttribArray(@attributes[:position])
|
130
|
+
GL.EnableVertexAttribArray(@attributes[:uv])
|
131
|
+
|
132
|
+
GL.BindBuffer(GL::ARRAY_BUFFER, @vertex_buffer)
|
133
|
+
|
134
|
+
GL.VertexAttribPointer(@attributes[:position], 2, GL::FLOAT, GL::FALSE, 2 * 8, 0)
|
135
|
+
GL.VertexAttribPointer(@attributes[:uv], 2, GL::FLOAT, GL::FALSE, 2 * 8, 8)
|
136
|
+
|
137
|
+
GL.BindBuffer(GL::ELEMENT_ARRAY_BUFFER, @element_buffer)
|
138
|
+
|
139
|
+
GL.UniformMatrix4fv(@uniforms[:projectionMatrix], 1, GL::FALSE, array_to_ptr_easy(camera.projection_matrix.elements))
|
140
|
+
|
141
|
+
GL.ActiveTexture(GL::TEXTURE0)
|
142
|
+
GL.Uniform1i(@uniforms[:map], 0)
|
143
|
+
end
|
144
|
+
|
145
|
+
def setup_fog(scene)
|
146
|
+
@old_fog_type = 0
|
147
|
+
@scene_fog_type = 0
|
148
|
+
fog = scene.fog
|
149
|
+
|
150
|
+
if fog
|
151
|
+
GL.Uniform3f(@uniforms[:fogColor], fog.color.r, fog.color.g, fog.color.b)
|
152
|
+
|
153
|
+
if fog.is_a?(Fog)
|
154
|
+
GL.Uniform1f(@uniforms[:fogNear], fog.near)
|
155
|
+
GL.Uniform1f(@uniforms[:fogFar], fog.far)
|
156
|
+
|
157
|
+
GL.Uniform1i(@uniforms[:fogType], 1)
|
158
|
+
@old_fog_type = 1
|
159
|
+
@scene_fog_type = 1
|
160
|
+
elsif fog.is_a?(FogExp2)
|
161
|
+
GL.Uniform1f(@uniforms[:fogDensity], fog.density)
|
162
|
+
|
163
|
+
GL.Uniform1i(@uniforms[:fogType], 2)
|
164
|
+
@old_fog_type = 2
|
165
|
+
@scene_fog_type = 2
|
166
|
+
end
|
167
|
+
else
|
168
|
+
GL.Uniform1i(@uniforms[:fogType], 0)
|
169
|
+
@old_fog_type = 0
|
170
|
+
@scene_fog_type = 0
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def update_positions_and_sort(camera)
|
175
|
+
@sprites.each do |sprite|
|
176
|
+
sprite.model_view_matrix.multiply_matrices(camera.matrix_world_inverse, sprite.matrix_world)
|
177
|
+
sprite.z = -sprite.model_view_matrix.elements[14]
|
178
|
+
end
|
179
|
+
|
180
|
+
@sprites.sort!(&self.method(:painter_sort_stable))
|
181
|
+
end
|
182
|
+
|
183
|
+
def render_all_sprites(scene)
|
184
|
+
@sprites.each do |sprite|
|
185
|
+
material = sprite.material
|
186
|
+
|
187
|
+
set_fog_uniforms(material, scene)
|
188
|
+
set_uv_uniforms(material)
|
189
|
+
set_color_uniforms(material)
|
190
|
+
set_transform_uniforms(sprite)
|
191
|
+
set_blend_mode(material)
|
192
|
+
|
193
|
+
# set texture
|
194
|
+
if material.map && material.map.image && material.map.image.width
|
195
|
+
material.map.set(0, @renderer)
|
196
|
+
else
|
197
|
+
# TODO: canvas texture?
|
198
|
+
# texture.set(0, @renderer)
|
199
|
+
end
|
200
|
+
|
201
|
+
# draw elements
|
202
|
+
GL.DrawElements(GL::TRIANGLES, 6, GL::UNSIGNED_INT, 0) # GL::UNSIGNED_SHORT
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def set_fog_uniforms(material, scene)
|
207
|
+
fog_type = 0
|
208
|
+
|
209
|
+
if scene.fog && material.fog
|
210
|
+
fog_type = @scene_fog_type
|
211
|
+
end
|
212
|
+
|
213
|
+
if @old_fog_type != fog_type
|
214
|
+
GL.Uniform1(@uniforms[:fogType], fog_type)
|
215
|
+
@old_fog_type = fog_type
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def set_uv_uniforms(material)
|
220
|
+
if !material.map.nil?
|
221
|
+
GL.Uniform2f(@uniforms[:uvOffset], material.map.offset.x, material.map.offset.y)
|
222
|
+
GL.Uniform2f(@uniforms[:uvScale], material.map.repeat.x, material.map.repeat.y)
|
223
|
+
else
|
224
|
+
GL.Uniform2f(@uniforms[:uvOffset], 0.0, 0.0)
|
225
|
+
GL.Uniform2f(@uniforms[:uvScale], 1.0, 1.0)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def set_color_uniforms(material)
|
230
|
+
GL.Uniform1f(@uniforms[:opacity], material.opacity)
|
231
|
+
GL.Uniform3f(@uniforms[:color], material.color.r, material.color.g, material.color.b)
|
232
|
+
GL.Uniform1f(@uniforms[:alphaTest], material.alpha_test)
|
233
|
+
end
|
234
|
+
|
235
|
+
def set_transform_uniforms(sprite)
|
236
|
+
GL.UniformMatrix4fv(@uniforms[:modelViewMatrix], 1, GL::FALSE, array_to_ptr_easy(sprite.model_view_matrix.elements))
|
237
|
+
|
238
|
+
sprite.matrix_world.decompose(@sprite_position, @sprite_rotation, @sprite_scale)
|
239
|
+
|
240
|
+
GL.Uniform1f(@uniforms[:rotation], sprite.material.rotation)
|
241
|
+
GL.Uniform2fv(@uniforms[:scale], 1, array_to_ptr_easy([@sprite_scale.x, @sprite_scale.y]))
|
242
|
+
end
|
243
|
+
|
244
|
+
def set_blend_mode(material)
|
245
|
+
@renderer.state.set_blending(material.blending, material.blend_equation, material.blend_src, material.blend_dst)
|
246
|
+
@renderer.state.set_depth_test(material.depth_test)
|
247
|
+
@renderer.state.set_depth_write(material.depth_write)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|