diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 070616f0619..9e2d10c1f66 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -512,7 +512,7 @@ CameraMatrix CameraMatrix::operator*(const CameraMatrix &p_matrix) const { return new_matrix; } -void CameraMatrix::set_depth_correction() { +void CameraMatrix::set_depth_correction(bool p_flip_y) { real_t *m = &matrix[0][0]; @@ -521,7 +521,7 @@ void CameraMatrix::set_depth_correction() { m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; - m[5] = -1; + m[5] = p_flip_y ? -1 : 1; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 2a251093679..b5c75ca562f 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -50,7 +50,7 @@ struct CameraMatrix { void set_identity(); void set_zero(); void set_light_bias(); - void set_depth_correction(); + void set_depth_correction(bool p_flip_y = true); void set_light_atlas_rect(const Rect2 &p_rect); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 7423d3ca384..fe682618a42 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -38,6 +38,7 @@ #include "core/self_list.h" class RasterizerScene { + public: /* SHADOW ATLAS API */ @@ -218,10 +219,15 @@ public: virtual void light_instance_mark_visible(RID p_light_instance) = 0; virtual bool light_instances_can_render_shadow_cube() const { return true; } + virtual RID reflection_atlas_create() = 0; + virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0; + virtual RID reflection_probe_instance_create(RID p_probe) = 0; virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0; + virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; - virtual void reflection_probe_instance_begin_render(RID p_instance) = 0; + virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0; virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0; virtual RID gi_probe_instance_create() = 0; @@ -229,7 +235,7 @@ public: virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; virtual void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) = 0; - virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; + virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0; virtual void set_scene_pass(uint64_t p_pass) = 0; @@ -246,6 +252,9 @@ public: }; class RasterizerStorage { + + Color default_clear_color; + public: /* TEXTURE API */ @@ -620,6 +629,14 @@ public: static RasterizerStorage *base_singleton; + void set_default_clear_color(const Color &p_color) { + default_clear_color = p_color; + } + + Color get_default_clear_color() const { + return default_clear_color; + } + RasterizerStorage(); virtual ~RasterizerStorage() {} }; diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp index e1aec58b96e..be5b8f18459 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp @@ -614,6 +614,30 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, uint32_t spot_count = 0; uint32_t decal_count = 0; + if (!e->instance->reflection_probe_instances.empty()) { + + uint32_t rpi_count = e->instance->reflection_probe_instances.size(); + const RID *rpi_ptrs = e->instance->reflection_probe_instances.ptr(); + + for (uint32_t j = 0; j < rpi_count; j++) { + if (render_pass != reflection_probe_instance_get_render_pass(rpi_ptrs[j])) { + continue; //not rendered this frame + } + + RID base = reflection_probe_instance_get_probe(rpi_ptrs[j]); + + uint32_t mask = storage->reflection_probe_get_cull_mask(base); + if (!(mask & id.mask)) { + continue; //masked + } + + if (reflection_count < 8) { + id.omni_light_indices[omni_count] = reflection_probe_instance_get_render_index(rpi_ptrs[j]); + reflection_count++; + } + } + } + if (!e->instance->light_instances.empty()) { uint32_t light_count = e->instance->light_instances.size(); const RID *light_ptrs = e->instance->light_instances.ptr(); @@ -832,12 +856,12 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l } } -void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) { +void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas) { //CameraMatrix projection = p_cam_projection; //projection.flip_y(); // Vulkan and modern APIs use Y-Down CameraMatrix correction; - correction.set_depth_correction(); + correction.set_depth_correction(!p_reflection_probe.is_valid()); CameraMatrix projection = correction * p_cam_projection; //store camera into ubo @@ -909,7 +933,17 @@ void RasterizerSceneForwardRD::_setup_environment(RID p_render_target, RID p_env } } else { - if (p_render_target.is_valid()) { + + if (p_reflection_probe.is_valid() && !storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { + scene_state.ubo.use_ambient_light = true; + Color clear_color = storage->get_default_clear_color(); + clear_color = clear_color.to_linear(); + scene_state.ubo.ambient_light_color_energy[0] = clear_color.r; + scene_state.ubo.ambient_light_color_energy[1] = clear_color.g; + scene_state.ubo.ambient_light_color_energy[2] = clear_color.b; + scene_state.ubo.ambient_light_color_energy[3] = 1.0; + + } else if (p_render_target.is_valid()) { scene_state.ubo.use_ambient_light = true; Color clear_color = storage->render_target_get_clear_request_color(p_render_target); clear_color = clear_color.to_linear(); @@ -1284,11 +1318,11 @@ void RasterizerSceneForwardRD::_draw_sky(RD::DrawListID p_draw_list, RD::Framebu void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) { - for (uint32_t i = 0; i < p_reflection_probe_cull_count; i++) { + for (int i = 0; i < p_reflection_probe_cull_count; i++) { RID rpi = p_reflection_probe_cull_result[i]; - if (i >= scene_state.max_reflections) { + if (i >= (int)scene_state.max_reflections) { reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set continue; } @@ -1304,14 +1338,14 @@ void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_r reflection_ubo.box_extents[0] = extents.x; reflection_ubo.box_extents[1] = extents.y; reflection_ubo.box_extents[2] = extents.z; - reflection_ubo.box_extents[3] = 0; + reflection_ubo.index = reflection_probe_instance_get_atlas_index(rpi); Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe); reflection_ubo.box_offset[0] = origin_offset.x; reflection_ubo.box_offset[1] = origin_offset.y; reflection_ubo.box_offset[2] = origin_offset.z; - reflection_ubo.box_offset[3] = 0; + reflection_ubo.mask = storage->reflection_probe_get_cull_mask(base_probe); float intensity = storage->reflection_probe_get_intensity(base_probe); bool interior = storage->reflection_probe_is_interior(base_probe); @@ -1350,6 +1384,8 @@ void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_r Transform transform = reflection_probe_instance_get_transform(rpi); Transform proj = (p_camera_inverse_transform * transform).inverse(); store_transform(proj, reflection_ubo.local_matrix); + + reflection_probe_instance_set_render_pass(rpi, render_pass); } if (p_reflection_probe_cull_count) { @@ -1357,7 +1393,7 @@ void RasterizerSceneForwardRD::_setup_reflections(RID *p_reflection_probe_cull_r } } -void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas) { +void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows) { uint32_t light_count = 0; scene_state.ubo.directional_light_count = 0; @@ -1406,7 +1442,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.shadow_color[1] = shadow_col.g; light_data.shadow_color[2] = shadow_col.b; - light_data.shadow_enabled = storage->light_has_shadow(base); + light_data.shadow_enabled = p_using_shadows && storage->light_has_shadow(base); if (light_data.shadow_enabled) { @@ -1481,7 +1517,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig Color shadow_color = storage->light_get_shadow_color(base); - bool has_shadow = storage->light_has_shadow(base); + bool has_shadow = p_using_shadows && storage->light_has_shadow(base); light_data.shadow_color_enabled[0] = CLAMP(uint32_t(shadow_color.r * 255), 0, 255); light_data.shadow_color_enabled[1] = CLAMP(uint32_t(shadow_color.g * 255), 0, 255); light_data.shadow_color_enabled[2] = CLAMP(uint32_t(shadow_color.b * 255), 0, 255); @@ -1492,7 +1528,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig light_data.atlas_rect[2] = 0; light_data.atlas_rect[3] = 0; - if (storage->light_has_shadow(base) && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) { + if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) { // fill in the shadow information Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas); @@ -1540,7 +1576,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig } } -void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { +void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)p_buffer_data; @@ -1569,8 +1605,14 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); } #endif + + bool using_shadows = true; + if (p_reflection_probe.is_valid()) { scene_state.ubo.reflection_multiplier = 0.0; + if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_reflection_probe))) { + using_shadows = false; + } } else { scene_state.ubo.reflection_multiplier = 1.0; } @@ -1605,13 +1647,17 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass); alpha_framebuffer = opaque_framebuffer; + if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { + p_environment = RID(); //no environment on interiors + } + } else { ERR_FAIL(); //bug? } - _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas); + _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows); _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment); - _setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas); + _setup_environment(render_target, p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas); #if 0 for (int i = 0; i < p_light_cull_count; i++) { @@ -1983,12 +2029,15 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co } break; } } else { - if (render_target.is_valid()) { + + if (p_reflection_probe.is_valid() && !storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) { + clear_color = storage->get_default_clear_color(); + } else if (render_target.is_valid()) { clear_color = storage->render_target_get_clear_request_color(render_target); } } - _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, RID()); + _setup_render_base_uniform_set(RID(), RID(), RID(), RID(), radiance_cubemap, p_shadow_atlas, p_reflection_atlas); render_list.sort_by_key(false); @@ -2236,7 +2285,7 @@ void RasterizerSceneForwardRD::_render_shadow(RID p_framebuffer, InstanceBase ** scene_state.ubo.z_far = p_zfar; scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - _setup_environment(RID(), RID(), p_projection, p_transform, true, Vector2(1, 1), RID()); + _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID()); render_list.clear(); @@ -2363,8 +2412,22 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer } { + + RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); RD::Uniform u; u.binding = 11; + u.type = RD::UNIFORM_TYPE_TEXTURE; + if (ref_texture.is_valid()) { + u.ids.push_back(ref_texture); + } else { + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK)); + } + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 12; u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(scene_state.light_buffer); uniforms.push_back(u); @@ -2372,7 +2435,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer { RD::Uniform u; - u.binding = 12; + u.binding = 13; u.type = RD::UNIFORM_TYPE_TEXTURE; if (p_shadow_atlas.is_valid()) { u.ids.push_back(shadow_atlas_get_texture(p_shadow_atlas)); @@ -2384,7 +2447,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer { RD::Uniform u; - u.binding = 13; + u.binding = 14; u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(scene_state.directional_light_buffer); uniforms.push_back(u); @@ -2392,7 +2455,7 @@ void RasterizerSceneForwardRD::_setup_render_base_uniform_set(RID p_depth_buffer { RD::Uniform u; - u.binding = 14; + u.binding = 15; u.type = RD::UNIFORM_TYPE_TEXTURE; if (directional_shadow_get_texture().is_valid()) { u.ids.push_back(directional_shadow_get_texture()); @@ -2425,18 +2488,6 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; } - uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); - - if (textures_per_stage <= 16) { - //ARM pretty much, and very old Intel GPUs under Linux - scene_state.max_reflection_probes_per_instance = 4; //sad - } else { - //maximum 8 - scene_state.max_reflection_probes_per_instance = 8; - } - - defines += "\n#define MAX_REFLECTION_PROBES " + itos(scene_state.max_reflection_probes_per_instance) + "\n"; - uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE); { //reflections diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h index 3cf83f70352..c8166c3f886 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h @@ -209,8 +209,10 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { /* Scene State UBO */ struct ReflectionData { //should always be 128 bytes - float box_extents[4]; - float box_offset[4]; + float box_extents[3]; + float index; + float box_offset[3]; + uint32_t mask; float params[4]; // intensity, 0, interior , boxproject float ambient[4]; // ambient color, energy float local_matrix[16]; // up to here for spot and omni, rest is for directional @@ -480,8 +482,8 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { PASS_MODE_DEPTH_NORMAL_ROUGHNESS, }; - void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas); - void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas); + void _setup_environment(RID p_render_target, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas); + void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows); void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment); void _fill_instances(RenderList::Element **p_elements, int p_element_count); @@ -494,7 +496,7 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { void _draw_sky(RD::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, float p_alpha); protected: - virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip); public: diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index 1c035d5d556..63b65a8a156 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -4,38 +4,17 @@ void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) { - if (rd.radiance.is_valid()) { - //if size changes, everything must be cleared - RD::get_singleton()->free(rd.radiance); - //everything else gets dependency, erase, so just clean it up - rd.radiance = RID(); - rd.layers.clear(); - rd.radiance_base_cubemap = RID(); - } + rd.layers.clear(); + rd.radiance_base_cubemap = RID(); } -void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, bool p_quality) { +void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer) { //recreate radiance and all data - int mipmaps = Image::get_image_required_mipmaps(p_size, p_size, Image::FORMAT_RGBAH) + 1; - if (!p_quality) { - //use less mipmaps - mipmaps = MIN(8, mipmaps); - } + int mipmaps = p_mipmaps; uint32_t w = p_size, h = p_size; - if (sky_use_cubemap_array) { - //array (higher quality, 6 times more memory) - RD::TextureFormat tf; - tf.array_layers = roughness_layers * 6; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; - tf.mipmaps = mipmaps; - tf.width = w; - tf.height = h; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - rd.radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + if (p_use_array) { for (int i = 0; i < roughness_layers; i++) { ReflectionData::Layer layer; @@ -47,7 +26,7 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, mm.size.width = mmw; mm.size.height = mmh; for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, i * 6 + k, j); + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j); Vector fbtex; fbtex.push_back(mm.views[k]); mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); @@ -62,17 +41,6 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, } else { //regular cubemap, lower quality (aliasing, less memory) - RD::TextureFormat tf; - tf.array_layers = 6; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE; - tf.mipmaps = roughness_layers; - tf.width = w; - tf.height = h; - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - rd.radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); - ReflectionData::Layer layer; uint32_t mmw = w; uint32_t mmh = h; @@ -82,7 +50,7 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, mm.size.width = mmw; mm.size.height = mmh; for (int k = 0; k < 6; k++) { - mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, k, j); + mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j); Vector fbtex; fbtex.push_back(mm.views[k]); mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); @@ -95,11 +63,14 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, rd.layers.push_back(layer); } - rd.radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.radiance, 0, 0, RD::TEXTURE_SLICE_CUBEMAP); + rd.radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP); } void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality) { +#ifndef _MSC_VER +#warning TODO, should probably use this algorithm instead. Volunteers? - https://www.ppsloan.org/publications/ggx_filtering.pdf / https://github.com/dariomanesku/cmft +#endif if (sky_use_cubemap_array) { if (p_quality) { @@ -148,9 +119,9 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID } } -void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_quality, int p_cube_side) { +void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side) { - if (sky_use_cubemap_array) { + if (p_use_arrays) { if (p_quality) { //render directly to the layers @@ -220,6 +191,10 @@ void RasterizerSceneRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { } sky->radiance_size = p_radiance_size; _sky_invalidate(sky); + if (sky->radiance.is_valid()) { + RD::get_singleton()->free(sky->radiance); + sky->radiance = RID(); + } _clear_reflection_data(sky->reflection); } @@ -242,6 +217,10 @@ void RasterizerSceneRD::sky_set_texture(RID p_sky, RID p_panorama) { if (sky->panorama.is_valid()) { sky->panorama = RID(); + if (sky->radiance.is_valid()) { + RD::get_singleton()->free(sky->radiance); + sky->radiance = RID(); + } _clear_reflection_data(sky->reflection); } @@ -260,8 +239,45 @@ void RasterizerSceneRD::_update_dirty_skys() { //update sky configuration if texture is missing - if (sky->reflection.radiance.is_null()) { - _update_reflection_data(sky->reflection, sky->radiance_size, sky->mode == VS::SKY_MODE_QUALITY); + if (sky->radiance.is_null()) { + int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1; + if (sky->mode != VS::SKY_MODE_QUALITY) { + //use less mipmaps + mipmaps = MIN(8, mipmaps); + } + + uint32_t w = sky->radiance_size, h = sky->radiance_size; + + if (sky_use_cubemap_array) { + //array (higher quality, 6 times more memory) + RD::TextureFormat tf; + tf.array_layers = roughness_layers * 6; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.mipmaps = mipmaps; + tf.width = w; + tf.height = h; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + _update_reflection_data(sky->reflection, sky->radiance_size, mipmaps, true, sky->radiance, 0); + + } else { + //regular cubemap, lower quality (aliasing, less memory) + RD::TextureFormat tf; + tf.array_layers = 6; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.type = RD::TEXTURE_TYPE_CUBE; + tf.mipmaps = roughness_layers; + tf.width = w; + tf.height = h; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + _update_reflection_data(sky->reflection, sky->radiance_size, mipmaps, false, sky->radiance, 0); + } } RID panorama_texture = storage->texture_get_rd_texture(sky->panorama); @@ -295,7 +311,7 @@ RID RasterizerSceneRD::sky_get_radiance_texture_rd(RID p_sky) const { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, RID()); - return sky->reflection.radiance; + return sky->radiance; } RID RasterizerSceneRD::environment_create() { @@ -469,6 +485,42 @@ bool RasterizerSceneRD::is_environment(RID p_env) const { //////////////////////////////////////////////////////////// +RID RasterizerSceneRD::reflection_atlas_create() { + + ReflectionAtlas ra; + ra.count = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_count"); + ra.size = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_size"); + + return reflection_atlas_owner.make_rid(ra); +} + +void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { + + ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas); + ERR_FAIL_COND(!ra); + + if (ra->size == p_reflection_size && ra->count == p_reflection_count) { + return; //no changes + } + + if (ra->reflection.is_valid()) { + //clear and invalidate everything + RD::get_singleton()->free(ra->reflection); + ra->reflection = RID(); + + for (int i = 0; i < ra->reflections.size(); i++) { + if (ra->reflections[i].owner.is_null()) { + continue; + } + reflection_probe_release_atlas_index(ra->reflections[i].owner); + //rp->atlasindex clear + } + + ra->reflections.clear(); + } +} + +//////////////////////// RID RasterizerSceneRD::reflection_probe_instance_create(RID p_probe) { ReflectionProbeInstance rpi; rpi.probe = p_probe; @@ -483,6 +535,22 @@ void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance, rpi->dirty = true; } +void RasterizerSceneRD::reflection_probe_release_atlas_index(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + + if (rpi->atlas.is_null()) { + return; //nothing to release + } + ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + ERR_FAIL_COND(!atlas); + ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size()); + atlas->reflections.write[rpi->atlas_index].owner = RID(); + rpi->atlas_index = -1; + rpi->atlas = RID(); +} + bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); @@ -496,52 +564,93 @@ bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) { return true; } - if (rpi->current_resolution != storage->reflection_probe_get_resolution(rpi->probe)) { - return true; - } - if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS) { return true; } - return false; + return rpi->atlas_index == -1; } -void RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance) { +bool RasterizerSceneRD::reflection_probe_instance_has_reflection(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND(!rpi); - rpi->rendering = true; - rpi->processing_side = 0; + ERR_FAIL_COND_V(!rpi, false); - int probe_resolution = storage->reflection_probe_get_resolution(rpi->probe); - if (rpi->current_resolution != probe_resolution) { - //need to re-create everything - _clear_reflection_data(rpi->reflection); - _update_reflection_data(rpi->reflection, probe_resolution, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE); + return rpi->atlas.is_valid(); +} - rpi->current_resolution = probe_resolution; +bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { - if (rpi->depth_buffer.is_valid()) { - RD::get_singleton()->free(rpi->depth_buffer); + ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_reflection_atlas); + + ERR_FAIL_COND_V(!atlas, false); + + if (atlas->reflection.is_null()) { + { + //reflection atlas was unused, create: + RD::TextureFormat tf; + tf.array_layers = 6 * atlas->count; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.mipmaps = roughness_layers; + tf.width = atlas->size; + tf.height = atlas->size; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + + atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView()); } { + RD::TextureFormat tf; - tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; - tf.width = probe_resolution; - tf.height = probe_resolution; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - - rpi->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; + tf.width = atlas->size; + tf.height = atlas->size; + tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); } - - for (int i = 0; i < 6; i++) { - Vector fb; - fb.push_back(rpi->reflection.layers[0].mipmaps[0].views[i]); - fb.push_back(rpi->depth_buffer); - rpi->render_fb[i] = RD::get_singleton()->framebuffer_create(fb); + atlas->reflections.resize(atlas->count); + for (int i = 0; i < atlas->count; i++) { + _update_reflection_data(atlas->reflections.write[i].data, atlas->size, roughness_layers, false, atlas->reflection, i * 6); + for (int j = 0; j < 6; j++) { + Vector fb; + fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]); + fb.push_back(atlas->depth_buffer); + atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb); + } } } + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + if (rpi->atlas_index == -1) { + for (int i = 0; i < atlas->reflections.size(); i++) { + if (atlas->reflections[i].owner.is_null()) { + rpi->atlas_index = i; + break; + } + } + //find the one used last + if (rpi->atlas_index == -1) { + //everything is in use, find the one least used via LRU + uint64_t pass_min = 0; + + for (int i = 0; i < atlas->reflections.size(); i++) { + ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.getornull(atlas->reflections[i].owner); + if (rpi2->last_pass < pass_min) { + pass_min = rpi2->last_pass; + rpi->atlas_index = i; + } + } + } + } + + rpi->atlas = p_reflection_atlas; + rpi->rendering = true; + rpi->dirty = false; + rpi->processing_side = 0; + + return true; } bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instance) { @@ -549,15 +658,22 @@ bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instanc ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); ERR_FAIL_COND_V(!rpi->rendering, false); + ERR_FAIL_COND_V(rpi->atlas.is_null(), false); - _create_reflection_from_base_mipmap(rpi->reflection, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side); + ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + if (!atlas || rpi->atlas_index == -1) { + //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering) + rpi->rendering = false; + return false; + } + + _create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side); rpi->processing_side++; if (rpi->processing_side == 6) { rpi->rendering = false; rpi->processing_side = 0; - return true; } else { return false; @@ -568,7 +684,9 @@ uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_insta ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, 0); - return rpi->current_resolution; + ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + ERR_FAIL_COND_V(!atlas, 0); + return atlas->size; } RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { @@ -576,7 +694,9 @@ RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, ERR_FAIL_COND_V(!rpi, RID()); ERR_FAIL_INDEX_V(p_index, 6, RID()); - return rpi->render_fb[p_index]; + ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + ERR_FAIL_COND_V(!atlas, RID()); + return atlas->reflections[rpi->atlas_index].fbs[p_index]; } /////////////////////////////////////////////////////////// @@ -591,8 +711,8 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(p_size < 0); - p_size = next_power_of_2(p_size); + p_size = MAX(p_size, 1 << roughness_layers); if (p_size == shadow_atlas->size) return; @@ -1097,12 +1217,12 @@ bool RasterizerSceneRD::is_using_radiance_cubemap_array() const { return sky_use_cubemap_array; } -void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { +void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb && p_render_buffers.is_valid()); - _render_scene(rb->data, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_probe, p_reflection_probe_pass); + _render_scene(rb ? rb->data : (RenderBufferData *)NULL, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass); } void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { @@ -1289,14 +1409,21 @@ bool RasterizerSceneRD::free(RID p_rid) { } else if (environment_owner.owns(p_rid)) { //not much to delete, just free it environment_owner.free(p_rid); + } else if (reflection_atlas_owner.owns(p_rid)) { + reflection_atlas_set_size(p_rid, 0, 0); + reflection_atlas_owner.free(p_rid); } else if (reflection_probe_instance_owner.owns(p_rid)) { //not much to delete, just free it ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid); - _clear_reflection_data(rpi->reflection); + reflection_probe_release_atlas_index(p_rid); reflection_probe_instance_owner.free(p_rid); } else if (sky_owner.owns(p_rid)) { _update_dirty_skys(); Sky *sky = sky_owner.getornull(p_rid); + if (sky->radiance.is_valid()) { + RD::get_singleton()->free(sky->radiance); + sky->radiance = RID(); + } _clear_reflection_data(sky->reflection); sky_owner.free(p_rid); } else if (light_instance_owner.owns(p_rid)) { @@ -1340,7 +1467,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { sky_ggx_samples_quality = GLOBAL_GET("rendering/quality/reflections/ggx_samples"); sky_ggx_samples_realtime = GLOBAL_GET("rendering/quality/reflections/ggx_samples_realtime"); sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); - sky_use_cubemap_array = false; + // sky_use_cubemap_array = false; } RasterizerSceneRD::~RasterizerSceneRD() { diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h index a6d3d6b4d1e..a1897cabe13 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h @@ -15,7 +15,7 @@ protected: }; virtual RenderBufferData *_create_render_buffer_data() = 0; - virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; + virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip) = 0; private: @@ -24,7 +24,6 @@ private: RasterizerStorageRD *storage; struct ReflectionData { - RID radiance; struct Layer { struct Mipmap { @@ -40,13 +39,14 @@ private: }; void _clear_reflection_data(ReflectionData &rd); - void _update_reflection_data(ReflectionData &rd, int p_size, bool p_quality); + void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer); void _create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality); - void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_quality, int p_cube_side); + void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side); void _update_reflection_mipmaps(ReflectionData &rd, bool p_quality); /* SKY */ struct Sky { + RID radiance; int radiance_size = 256; VS::SkyMode mode = VS::SKY_MODE_QUALITY; RID panorama; @@ -66,22 +66,41 @@ private: mutable RID_Owner sky_owner; + /* REFLECTION ATLAS */ + + struct ReflectionAtlas { + + int count = 0; + int size = 0; + + RID reflection; + RID depth_buffer; + + struct Reflection { + RID owner; + ReflectionData data; + RID fbs[6]; + }; + + Vector reflections; + }; + + RID_Owner reflection_atlas_owner; + /* REFLECTION PROBE INSTANCE */ struct ReflectionProbeInstance { RID probe; - - ReflectionData reflection; - RID depth_buffer; - RID render_fb[6]; - - int current_resolution = 0; + int atlas_index = -1; + RID atlas; bool dirty = true; bool rendering = false; int processing_side = 0; + uint32_t render_step = 0; + uint64_t last_pass = 0; uint32_t render_index = 0; Transform transform; @@ -453,10 +472,20 @@ public: return li->light_type; } + virtual RID reflection_atlas_create(); + virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count); + _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) { + ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas); + ERR_FAIL_COND_V(!atlas, RID()); + return atlas->reflection; + } + virtual RID reflection_probe_instance_create(RID p_probe); virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform); + virtual void reflection_probe_release_atlas_index(RID p_instance); virtual bool reflection_probe_instance_needs_redraw(RID p_instance); - virtual void reflection_probe_instance_begin_render(RID p_instance); + virtual bool reflection_probe_instance_has_reflection(RID p_instance); + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas); virtual bool reflection_probe_instance_postprocess_step(RID p_instance); uint32_t reflection_probe_instance_get_resolution(RID p_instance); @@ -482,6 +511,19 @@ public: return rpi->render_index; } + _FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + rpi->last_pass = p_render_pass; + } + + _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, 0); + + return rpi->last_pass; + } + _FORCE_INLINE_ Transform reflection_probe_instance_get_transform(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, Transform()); @@ -489,11 +531,11 @@ public: return rpi->transform; } - _FORCE_INLINE_ RID reflection_probe_instance_get_texture(RID p_instance) { + _FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!rpi, RID()); + ERR_FAIL_COND_V(!rpi, -1); - return rpi->reflection.radiance; + return rpi->atlas_index; } RID gi_probe_instance_create() { return RID(); } @@ -504,7 +546,7 @@ public: RID render_buffers_create(); void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa); - void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl index 1bed9f9672a..d64276a2bfb 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl @@ -710,6 +710,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a + void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo,float roughness, float metallic, float specular,float p_blob_intensity, #ifdef LIGHT_TRANSMISSION_USED vec3 transmission, @@ -781,6 +782,86 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a diffuse_light, specular_light); } +void reflection_process(uint ref_index, vec3 vertex, vec3 normal,float roughness,vec3 ambient_light,vec3 specular_light,inout vec4 ambient_accum, inout vec4 reflection_accum) { + + vec3 box_extents = reflections.data[ref_index].box_extents; + vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz; + + if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box + return; + } + + vec3 ref_vec = normalize(reflect(vertex, normal)); + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + //make blend more rounded + blend = mix(length(inner_pos), blend, blend); + blend *= blend; + blend = max(0.0, 1.0 - blend); + + if (reflections.data[ref_index].params.x > 0.0) { // compute reflection + + vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; + + if (reflections.data[ref_index].params.w > 0.5) { //box project + + vec3 nrdir = normalize(local_ref_vec); + vec3 rbmax = (box_extents - local_pos) / nrdir; + vec3 rbmin = (-box_extents - local_pos) / nrdir; + + vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + local_ref_vec = posonbox - reflections.data[ref_index].box_offset; + } + + vec4 reflection; + + reflection.rgb = textureLod(samplerCubeArray(reflection_atlas,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec,reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb; + + if (reflections.data[ref_index].params.z < 0.5) { + reflection.rgb = mix(specular_light, reflection.rgb, blend); + } + + reflection.rgb *= reflections.data[ref_index].params.x; + reflection.a = blend; + reflection.rgb *= reflection.a; + + reflection_accum += reflection; + } + +#ifndef USE_LIGHTMAP + if (reflections.data[ref_index].ambient.a > 0.0) { //compute ambient using skybox + + vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz; + + vec4 ambient_out; + + ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas,material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec,reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb; + + ambient_out.a = blend; + ambient_out.rgb = mix(reflections.data[ref_index].ambient.rgb, ambient_out.rgb, reflections.data[ref_index].ambient.a); + if (reflections.data[ref_index].params.z < 0.5) { + ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); + } + + ambient_out.rgb *= ambient_out.a; + ambient_accum += ambient_out; + } else { + + vec4 ambient_out; + ambient_out.a = blend; + ambient_out.rgb = reflections.data[ref_index].ambient.rgb; + if (reflections.data[ref_index].params.z < 0.5) { + ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); + } + ambient_out.rgb *= ambient_out.a; + ambient_accum += ambient_out; + } +#endif //USE_LIGHTMAP +} void main() { #ifdef MODE_DUAL_PARABOLOID @@ -976,126 +1057,28 @@ FRAGMENT_SHADER_CODE //lightmap capture -#if 0 + { // process reflections vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - for (uint i = 0; i < MAX_REFLECTION_PROBES; i++) { - if (i >= draw_data.reflection_probe_count) { - break; - } + uint reflection_probe_count = instances.data[instance_index].flags & INSTANCE_FLAGS_FORWARD_MASK; - uint ref_index; - if (i<4) { - if (i<2) { - ref_index=draw_data.reflection_probe_indices[0]; - } else { - ref_index=draw_data.reflection_probe_indices[1]; - } + for (uint i = 0; i < reflection_probe_count; i++) { + + + uint ref_index = instances.data[instance_index].reflection_probe_indices[i>>1]; + + if (bool(i&1)) { + ref_index>>=16; } else { - if (i<6) { - ref_index=draw_data.reflection_probe_indices[2]; - } else { - ref_index=draw_data.reflection_probe_indices[3]; - } - } - ref_index>>=(i&1)*16; - ref_index&=0xFFFF; - - vec3 box_extents = reflections.data[ref_index].box_extents.xyz; - vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz; - - if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box - continue; + ref_index&=0xFFFF; } - vec3 ref_vec = normalize(reflect(vertex, normal)); - vec3 inner_pos = abs(local_pos / box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - //make blend more rounded - blend = mix(length(inner_pos), blend, blend); - blend *= blend; - blend = max(0.0, 1.0 - blend); - - if (reflections.data[ref_index].params.x > 0.0) { // compute reflection - - vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; - - if (reflections.data[ref_index].params.w > 0.5) { //box project - - vec3 nrdir = normalize(local_ref_vec); - vec3 rbmax = (box_extents - local_pos) / nrdir; - vec3 rbmin = (-box_extents - local_pos) / nrdir; - - vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0))); - - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; - local_ref_vec = posonbox - reflections.data[ref_index].box_offset.xyz; - } - - vec4 reflection; - -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - - float lod,layer_blend; - layer_blend = modf(roughness * MAX_ROUGHNESS_LOD, lod); - reflection.rgb = texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, lod)).rgb; - reflection.rgb = mix(reflection.rgb,texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, lod+1)).rgb,layer_blend); - -#else - reflection.rgb = textureLod(samplerCube(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), local_ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; - -#endif - - if (reflections.data[ref_index].params.z < 0.5) { - reflection.rgb = mix(specular_light, reflection.rgb, blend); - } - - reflection.rgb *= reflections.data[ref_index].params.x; - reflection.a = blend; - reflection.rgb *= reflection.a; - - reflection_accum += reflection; - } - -#ifndef USE_LIGHTMAP - if (reflections.data[ref_index].ambient.a > 0.0) { //compute ambient using skybox - - vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz; - - vec4 ambient_out; - -#ifdef USE_RADIANCE_CUBEMAP_ARRAY - ambient_out.rgb = texture(samplerCubeArray(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, MAX_ROUGHNESS_LOD)).rgb; -#else - ambient_out.rgb = textureLod(samplerCube(reflection_probes[i],material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), local_amb_vec, MAX_ROUGHNESS_LOD).rgb; -#endif //USE_RADIANCE_CUBEMAP_ARRAY - - ambient_out.a = blend; - ambient_out.rgb = mix(reflections.data[ref_index].ambient.rgb, ambient_out.rgb, reflections.data[ref_index].ambient.a); - if (reflections.data[ref_index].params.z < 0.5) { - ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); - } - - ambient_out.rgb *= ambient_out.a; - ambient_accum += ambient_out; - } else { - - vec4 ambient_out; - ambient_out.a = blend; - ambient_out.rgb = reflections.data[ref_index].ambient.rgb; - if (reflections.data[ref_index].params.z < 0.5) { - ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); - } - ambient_out.rgb *= ambient_out.a; - ambient_accum += ambient_out; - } -#endif //USE_LIGHTMAP + reflection_process(ref_index,vertex,normal,roughness,ambient_light,specular_light,ambient_accum,reflection_accum); } @@ -1111,7 +1094,7 @@ FRAGMENT_SHADER_CODE } -#endif //0 + { #if defined(DIFFUSE_TOON) diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl index 3e6249e4cb9..d6b6aa43016 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl @@ -145,8 +145,10 @@ layout(set=0,binding=9,std430) buffer Instances { struct ReflectionData { - vec4 box_extents; - vec4 box_offset; + vec3 box_extents; + float index; + vec3 box_offset; + uint mask; vec4 params; // intensity, 0, interior , boxproject vec4 ambient; // ambient color, energy mat4 local_matrix; // up to here for spot and omni, rest is for directional @@ -157,6 +159,7 @@ layout(set=0,binding=10,std140) uniform ReflectionProbeData { ReflectionData data[MAX_REFLECTION_DATA_STRUCTS]; } reflections; +layout(set=0,binding=11) uniform textureCubeArray reflection_atlas; struct LightData { //this structure needs to be 128 bits @@ -172,11 +175,11 @@ struct LightData { //this structure needs to be 128 bits mat4 shadow_matrix; }; -layout(set=0,binding=11,std140) uniform Lights { +layout(set=0,binding=12,std140) uniform Lights { LightData data[MAX_LIGHT_DATA_STRUCTS]; } lights; -layout(set=0,binding=12) uniform texture2D shadow_atlas; +layout(set=0,binding=13) uniform texture2D shadow_atlas; struct DirectionalLightData { @@ -198,11 +201,11 @@ struct DirectionalLightData { }; -layout(set=0,binding=13,std140) uniform DirectionalLights { +layout(set=0,binding=14,std140) uniform DirectionalLights { DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; } directional_lights; -layout(set=0,binding=14) uniform texture2D directional_shadow_atlas; +layout(set=0,binding=15) uniform texture2D directional_shadow_atlas; /* layout(set=0,binding=15,std430) buffer Skeletons { diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index d060043b404..3f33ec945c4 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -268,7 +268,7 @@ RID VisualServerScene::scenario_create() { VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4); VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4); VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8); - + scenario->reflection_atlas = VSG::scene_render->reflection_atlas_create(); return scenario_rid; } @@ -293,6 +293,13 @@ void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_ scenario->fallback_environment = p_environment; } +void VisualServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) { + + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + VSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count); +} + /* INSTANCING API */ void VisualServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) { @@ -510,6 +517,8 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) { } } break; case VS::INSTANCE_REFLECTION_PROBE: { + InstanceReflectionProbeData *reflection_probe = static_cast(instance->base_data); + VSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); } break; case VS::INSTANCE_GI_PROBE: { @@ -1808,7 +1817,7 @@ void VisualServerScene::render_camera(RID p_render_buffers, Ref & _render_scene(p_render_buffers, cam_transform, camera_matrix, false, camera->env, p_scenario, p_shadow_atlas, RID(), -1); }; -void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe) { +void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) { // Note, in stereo rendering: // - p_cam_transform will be a transform in the middle of our two eyes // - p_cam_projection is a wider frustrum that encompasses both eyes @@ -1894,8 +1903,10 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca reflection_probe->reflection_dirty = false; } - reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance; - reflection_probe_cull_count++; + if (VSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) { + reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance; + reflection_probe_cull_count++; + } } } } @@ -2015,7 +2026,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca //check shadow.. if (light) { - if (p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(E->get()->base)) { + if (p_using_shadows && p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(E->get()->base)) { lights_with_shadow[directional_shadow_count++] = E->get(); } //add to list @@ -2031,7 +2042,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca } } - { //setup shadow maps + if (p_using_shadows) { //setup shadow maps //SortArray sorter; //sorter.sort(light_cull_result,light_cull_count); @@ -2148,7 +2159,7 @@ void VisualServerScene::_render_scene(RID p_render_buffers, const Transform p_ca /* PROCESS GEOMETRY AND DRAW SCENE */ - VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe, p_reflection_probe_pass); + VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass); } void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { @@ -2162,7 +2173,7 @@ void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, environment = scenario->environment; else environment = scenario->fallback_environment; - VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, RID(), 0); + VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0); #endif } @@ -2176,18 +2187,28 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int if (p_step == 0) { - VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance); + if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { + return true; //all full + } } if (p_step >= 0 && p_step < 6) { static const Vector3 view_normals[6] = { - Vector3(-1, 0, 0), Vector3(+1, 0, 0), - Vector3(0, -1, 0), + Vector3(-1, 0, 0), Vector3(0, +1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1) + }; + static const Vector3 view_up[6] = { + Vector3(0, -1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, +1), Vector3(0, 0, -1), - Vector3(0, 0, +1) + Vector3(0, -1, 0), + Vector3(0, -1, 0) }; Vector3 extents = VSG::storage->reflection_probe_get_extents(p_instance->base); @@ -2203,15 +2224,6 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int CameraMatrix cm; cm.set_perspective(90, 1, 0.01, max_distance); - static const Vector3 view_up[6] = { - Vector3(0, -1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, -1), - Vector3(0, 0, +1), - Vector3(0, -1, 0), - Vector3(0, -1, 0) - }; - Transform local_view; local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]); @@ -2219,12 +2231,13 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int RID shadow_atlas; - if (VSG::storage->reflection_probe_renders_shadows(p_instance->base)) { + bool use_shadows = VSG::storage->reflection_probe_renders_shadows(p_instance->base); + if (use_shadows) { shadow_atlas = scenario->reflection_probe_shadow_atlas; } - _prepare_scene(xform, cm, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance); + _prepare_scene(xform, cm, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows); _render_scene(RID(), xform, cm, false, RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step); } else { @@ -3465,6 +3478,7 @@ bool VisualServerScene::free(RID p_rid) { instance_set_scenario(scenario->instances.first()->self()->self, RID()); } VSG::scene_render->free(scenario->reflection_probe_shadow_atlas); + VSG::scene_render->free(scenario->reflection_atlas); scenario_owner.free(p_rid); memdelete(scenario); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 0f73f42153b..2fadd778be1 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -115,6 +115,7 @@ public: RID environment; RID fallback_environment; RID reflection_probe_shadow_atlas; + RID reflection_atlas; SelfList::List instances; @@ -131,6 +132,7 @@ public: virtual void scenario_set_debug(RID p_scenario, VS::ScenarioDebugMode p_debug_mode); virtual void scenario_set_environment(RID p_scenario, RID p_environment); virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count); /* INSTANCING API */ @@ -475,7 +477,7 @@ public: _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario); - void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe); + void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true); void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 5d2441be7bd..75a90d988b6 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -83,7 +83,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front int scenario_canvas_max_layer = 0; - Color bgcolor = clear_color; + Color bgcolor = VSG::storage->get_default_clear_color(); if (!p_viewport->hide_canvas && !p_viewport->disable_environment && VSG::scene->scenario_owner.owns(p_viewport->scenario)) { @@ -295,7 +295,7 @@ void VisualServerViewport::draw_viewports() { #endif if (Engine::get_singleton()->is_editor_hint()) { - clear_color = GLOBAL_GET("rendering/environment/default_clear_color"); + set_default_clear_color(GLOBAL_GET("rendering/environment/default_clear_color")); } //sort viewports @@ -719,7 +719,7 @@ bool VisualServerViewport::free(RID p_rid) { } void VisualServerViewport::set_default_clear_color(const Color &p_color) { - clear_color = p_color; + VSG::storage->set_default_clear_color(p_color); } VisualServerViewport::VisualServerViewport() { diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index eecbe0d1db3..30b53f3935c 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -148,7 +148,6 @@ public: Vector active_viewports; private: - Color clear_color; void _draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye); void _draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye = ARVRInterface::EYE_MONO); diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index af29f14b770..66e0d67938b 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2302,6 +2302,9 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/quality/reflections/ggx_samples.mobile", 128); GLOBAL_DEF("rendering/quality/reflections/ggx_samples_realtime", 64); GLOBAL_DEF("rendering/quality/reflections/ggx_samples_realtime.mobile", 16); + GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size", 256); + GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size.mobile", 128); + GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_count", 64); GLOBAL_DEF("rendering/quality/shading/force_vertex_shading", false); GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true);