From 231dbcaad7ae59d8be1549137e2b4e8f6a8908a1 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Thu, 20 Apr 2023 22:26:00 +1000 Subject: [PATCH] Stepped update of directional shadow maps --- doc/classes/ProjectSettings.xml | 3 + doc/classes/RenderingServer.xml | 27 +++ doc/classes/Viewport.xml | 15 ++ drivers/gles3/rasterizer_scene_gles3.cpp | 2 +- drivers/gles3/rasterizer_scene_gles3.h | 2 +- drivers/gles3/storage/light_storage.cpp | 2 +- drivers/gles3/storage/light_storage.h | 7 +- editor/editor_node.cpp | 3 + scene/main/viewport.cpp | 33 ++++ scene/main/viewport.h | 16 ++ .../rendering/dummy/rasterizer_scene_dummy.h | 2 +- .../rendering/dummy/storage/light_storage.h | 7 +- .../render_forward_clustered.cpp | 117 ++++++++---- .../render_forward_clustered.h | 6 +- .../forward_mobile/render_forward_mobile.cpp | 58 ++++-- .../forward_mobile/render_forward_mobile.h | 2 +- .../renderer_rd/renderer_scene_render_rd.cpp | 40 ++-- .../renderer_rd/renderer_scene_render_rd.h | 5 +- .../renderer_rd/storage_rd/light_storage.cpp | 133 +++++++++++--- .../renderer_rd/storage_rd/light_storage.h | 173 ++++++++++++++---- servers/rendering/renderer_scene_cull.cpp | 65 +++++-- servers/rendering/renderer_scene_render.h | 2 +- servers/rendering/renderer_viewport.cpp | 19 ++ servers/rendering/renderer_viewport.h | 5 + servers/rendering/rendering_server_default.h | 3 + servers/rendering/storage/light_storage.h | 7 +- servers/rendering_server.cpp | 9 + servers/rendering_server.h | 11 ++ 28 files changed, 624 insertions(+), 150 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 949253c99895..3f0661c8e217 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2177,6 +2177,9 @@ Lower-end override for [member rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality] on mobile devices, due to performance concerns or driver support. + + Sets the default cascade step mode applied to our viewports. + Use 16 bits for shadow depth map. Enabling this results in shadows having less precision and may result in shadow acne, but can lead to performance improvements on some devices. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 5f9abe2cda15..f18a152b63e5 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3195,6 +3195,13 @@ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. + + + + + Obtain the cascade step mode for a given viewport. + + @@ -3266,6 +3273,14 @@ Sets the transformation of a viewport's canvas. + + + + + + Sets the cascade step mode of a viewport. See [enum ViewportCascadeMode] for options. + + @@ -4354,6 +4369,18 @@ Represents the size of the [enum ViewportVRSMode] enum. + + All directional shadow map cascades are updated each frame. + + + Cascades 1 and 2 are updated each frame, 3 and 4 alternate between frames. + + + Cascades are updated in the following repeating sequence: 1 + 2, 1 + 3, 1 + 2, 1 + 4. + + + Representes the size of the [enum ViewportCascadeMode] enum. + diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 7c131202c831..76c2a5a23ff3 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -238,6 +238,9 @@ The overlay mode for test rendered geometry in debug purposes. + + The directinal shadow map cascade mode. See [enum CascadeMode] for options. + Disable 3D rendering (but keep 2D rendering). @@ -582,5 +585,17 @@ Represents the size of the [enum VRSMode] enum. + + All directional shadow map cascades are updated each frame. + + + Cascades 1 and 2 are updated each frame, 3 and 4 alternate between frames. + + + Cascades are updated in the following repeating sequence: 1 + 2, 1 + 3, 1 + 2, 1 + 4. + + + Representes the size of the [enum CascadeMode] enum. + diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 3d8f7924a78b..46604a934fc6 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1696,7 +1696,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b glBindBuffer(GL_UNIFORM_BUFFER, 0); } -void RasterizerSceneGLES3::render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) { +void RasterizerSceneGLES3::render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_viewport, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::Config *config = GLES3::Config::get_singleton(); RENDER_TIMESTAMP("Setup 3D Scene"); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index b4e787ad857d..79a14b6fa66f 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -646,7 +646,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { void voxel_gi_set_quality(RS::VoxelGIQuality) override; - void render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override; + void render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_viewport, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override; void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) override; void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray &p_instances) override; diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 026f7467a8f8..9d4c1bf5cae1 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -374,7 +374,7 @@ void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_a light_instance->aabb = p_aabb; } -void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { +void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale, RID p_viewport) { } void LightStorage::light_instance_mark_visible(RID p_light_instance) { diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index 8e6480869b7b..9cb6462014a1 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -302,7 +302,7 @@ class LightStorage : public RendererLightStorage { virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2(), RID p_viewport = RID()) override; virtual void light_instance_mark_visible(RID p_light_instance) override; _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) { @@ -423,6 +423,11 @@ class LightStorage : public RendererLightStorage { virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override; virtual int get_directional_light_shadow_size(RID p_light_intance) override; virtual void set_directional_shadow_count(int p_count) override; + + virtual bool directional_shadow_get_needs_full_update(RID p_viewport) const override { return false; } + virtual void directional_shadow_set_needs_full_update(RID p_viewport, bool p_needs_update) override {} + + virtual void cleanup_directional_shadow_viewport(RID p_viewport) override {} }; } // namespace GLES3 diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 3681f61cd8b3..3e9fdd37e6bc 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -535,6 +535,9 @@ void EditorNode::_update_from_settings() { Viewport::MSAA msaa = Viewport::MSAA(int(GLOBAL_GET("rendering/anti_aliasing/quality/msaa_2d"))); scene_root->set_msaa_2d(msaa); + Viewport::CascadeMode cascade_mode = Viewport::CascadeMode(int(GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/step_cascades"))); + scene_root->set_cascade_mode(cascade_mode); + float mesh_lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels"); scene_root->set_mesh_lod_threshold(mesh_lod_threshold); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index f3c2f4b0ccfd..0f01635b3e95 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3276,6 +3276,26 @@ Ref Viewport::get_vrs_texture() const { return vrs_texture; } +void Viewport::set_cascade_mode(Viewport::CascadeMode p_cascade_mode) { + cascade_mode = p_cascade_mode; + + switch (cascade_mode) { + case CASCADE_TWOSTEP: { + RS::get_singleton()->viewport_set_cascade_mode(viewport, RS::VIEWPORT_CASCADE_TWOSTEP); + } break; + case CASCADE_FOURSTEP: { + RS::get_singleton()->viewport_set_cascade_mode(viewport, RS::VIEWPORT_CASCADE_FOURSTEP); + } break; + default: { + RS::get_singleton()->viewport_set_cascade_mode(viewport, RS::VIEWPORT_CASCADE_ALL); + } break; + } +} + +Viewport::CascadeMode Viewport::get_cascade_mode() const { + return cascade_mode; +} + DisplayServer::WindowID Viewport::get_window_id() const { return DisplayServer::MAIN_WINDOW_ID; } @@ -3993,6 +4013,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_vrs_texture", "texture"), &Viewport::set_vrs_texture); ClassDB::bind_method(D_METHOD("get_vrs_texture"), &Viewport::get_vrs_texture); + ClassDB::bind_method(D_METHOD("set_cascade_mode", "mode"), &Viewport::set_cascade_mode); + ClassDB::bind_method(D_METHOD("get_cascade_mode"), &Viewport::get_cascade_mode); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d"); @@ -4040,6 +4063,10 @@ void Viewport::_bind_methods() { ADD_GROUP("SDF", "sdf_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"), "set_sdf_oversize", "get_sdf_oversize"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_scale", PROPERTY_HINT_ENUM, "100%,50%,25%"), "set_sdf_scale", "get_sdf_scale"); +#ifndef _3D_DISABLED + ADD_GROUP("Directional Shadow Atlas", "directional_shadow_atlas_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_atlas_cascade_mode", PROPERTY_HINT_ENUM, "All (Slowest),Two step (Faster),Four step (Fastest)"), "set_cascade_mode", "get_cascade_mode"); +#endif ADD_GROUP("Positional Shadow Atlas", "positional_shadow_atlas_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "positional_shadow_atlas_size"), "set_positional_shadow_atlas_size", "get_positional_shadow_atlas_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "positional_shadow_atlas_16_bits"), "set_positional_shadow_atlas_16_bits", "get_positional_shadow_atlas_16_bits"); @@ -4139,6 +4166,11 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(VRS_TEXTURE); BIND_ENUM_CONSTANT(VRS_XR); BIND_ENUM_CONSTANT(VRS_MAX); + + BIND_ENUM_CONSTANT(CASCADE_ALL); + BIND_ENUM_CONSTANT(CASCADE_TWOSTEP); + BIND_ENUM_CONSTANT(CASCADE_FOURSTEP); + BIND_ENUM_CONSTANT(CASCADE_MAX); } void Viewport::_validate_property(PropertyInfo &p_property) const { @@ -4187,6 +4219,7 @@ Viewport::Viewport() { set_scaling_3d_scale(GLOBAL_GET("rendering/scaling_3d/scale")); set_fsr_sharpness((float)GLOBAL_GET("rendering/scaling_3d/fsr_sharpness")); set_texture_mipmap_bias((float)GLOBAL_GET("rendering/textures/default_filters/texture_mipmap_bias")); + set_cascade_mode(CascadeMode(int(GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/step_cascades")))); #endif // _3D_DISABLED set_sdf_oversize(sdf_oversize); // Set to server. diff --git a/scene/main/viewport.h b/scene/main/viewport.h index f12e7921a3d8..89b49b85d83a 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -204,6 +204,13 @@ class Viewport : public Node { VRS_MAX }; + enum CascadeMode { + CASCADE_ALL, + CASCADE_TWOSTEP, + CASCADE_FOURSTEP, + CASCADE_MAX + }; + private: friend class ViewportTexture; @@ -348,6 +355,9 @@ class Viewport : public Node { VRSMode vrs_mode = VRS_DISABLED; Ref vrs_texture; + // Directional shadow cascade + CascadeMode cascade_mode = CASCADE_ALL; + struct GUI { // info used when this is a window @@ -638,6 +648,11 @@ class Viewport : public Node { void set_vrs_texture(Ref p_texture); Ref get_vrs_texture() const; + // Directional shadow cascade + + void set_cascade_mode(CascadeMode p_cascade_mode); + CascadeMode get_cascade_mode() const; + virtual DisplayServer::WindowID get_window_id() const = 0; void set_embedding_subwindows(bool p_embed); @@ -802,6 +817,7 @@ VARIANT_ENUM_CAST(Viewport::DebugDraw); VARIANT_ENUM_CAST(Viewport::SDFScale); VARIANT_ENUM_CAST(Viewport::SDFOversize); VARIANT_ENUM_CAST(Viewport::VRSMode); +VARIANT_ENUM_CAST(Viewport::CascadeMode); VARIANT_ENUM_CAST(SubViewport::ClearMode); VARIANT_ENUM_CAST(Viewport::RenderInfo); VARIANT_ENUM_CAST(Viewport::RenderInfoType); diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 965d837ea80e..47c138f31350 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -145,7 +145,7 @@ class RasterizerSceneDummy : public RendererSceneRender { void voxel_gi_set_quality(RS::VoxelGIQuality) override {} - void render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_info = nullptr) override {} + void render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_viewport, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_info = nullptr) override {} void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) override {} void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray &p_instances) override {} diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h index b9e8bcc6f19e..12b3e39546ff 100644 --- a/servers/rendering/dummy/storage/light_storage.h +++ b/servers/rendering/dummy/storage/light_storage.h @@ -88,7 +88,7 @@ class LightStorage : public RendererLightStorage { void light_instance_free(RID p_light) override {} void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override {} void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {} - void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {} + void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2(), RID p_viewport = RID()) override {} void light_instance_mark_visible(RID p_light_instance) override {} /* PROBE API */ @@ -178,6 +178,11 @@ class LightStorage : public RendererLightStorage { virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override {} virtual int get_directional_light_shadow_size(RID p_light_intance) override { return 0; } virtual void set_directional_shadow_count(int p_count) override {} + + virtual bool directional_shadow_get_needs_full_update(RID p_viewport) const override { return false; } + virtual void directional_shadow_set_needs_full_update(RID p_viewport, bool p_needs_update) override {} + + virtual void cleanup_directional_shadow_viewport(RID p_viewport) override {} }; } // namespace RendererDummy diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index c7d85a3bbf23..f149a485d343 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1148,9 +1148,11 @@ void RenderForwardClustered::_debug_draw_cluster(Ref p_ren //////////////////////////////////////////////////////////////////////////////// // FOG SHADER -void RenderForwardClustered::_update_volumetric_fog(Ref p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes) { +void RenderForwardClustered::_update_volumetric_fog(Ref p_render_buffers, RID p_viewport, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes) { ERR_FAIL_COND(p_render_buffers.is_null()); + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + Ref rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); ERR_FAIL_COND(rb_data.is_null()); @@ -1197,16 +1199,22 @@ void RenderForwardClustered::_update_volumetric_fog(Ref p_ settings.rb_size = size; settings.time = time; settings.is_using_radiance_cubemap_array = is_using_radiance_cubemap_array(); - settings.max_cluster_elements = RendererRD::LightStorage::get_singleton()->get_max_cluster_elements(); + settings.max_cluster_elements = light_storage->get_max_cluster_elements(); settings.volumetric_fog_filter_active = get_volumetric_fog_filter_active(); settings.shadow_sampler = shadow_sampler; - settings.shadow_atlas_depth = RendererRD::LightStorage::get_singleton()->owns_shadow_atlas(p_shadow_atlas) ? RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_shadow_atlas) : RID(); + settings.shadow_atlas_depth = light_storage->owns_shadow_atlas(p_shadow_atlas) ? light_storage->shadow_atlas_get_texture(p_shadow_atlas) : RID(); settings.voxel_gi_buffer = rbgi->get_voxel_gi_buffer(); - settings.omni_light_buffer = RendererRD::LightStorage::get_singleton()->get_omni_light_buffer(); - settings.spot_light_buffer = RendererRD::LightStorage::get_singleton()->get_spot_light_buffer(); - settings.directional_shadow_depth = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture(); - settings.directional_light_buffer = RendererRD::LightStorage::get_singleton()->get_directional_light_buffer(); + settings.omni_light_buffer = light_storage->get_omni_light_buffer(); + settings.spot_light_buffer = light_storage->get_spot_light_buffer(); + + bool step_cascades = p_viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_viewport) != RS::VIEWPORT_CASCADE_ALL : false; + if (step_cascades) { + settings.directional_shadow_depth = light_storage->directional_shadow_get_texture(p_viewport); + } else { + settings.directional_shadow_depth = light_storage->directional_shadow_get_texture(); + } + settings.directional_light_buffer = light_storage->get_directional_light_buffer(); settings.vfog = fog; settings.cluster_builder = rb_data->cluster_builder; @@ -1369,14 +1377,24 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo //cube shadows are rendered in their own way for (const int &index : p_render_data->cube_shadows) { - _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + _render_shadow_pass(p_render_data->viewport, p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, rb); } if (p_render_data->directional_shadows.size()) { - //open the pass for directional shadows - light_storage->update_directional_shadow_atlas(); - RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE); - RD::get_singleton()->draw_list_end(); + bool step_cascades = p_render_data->viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_render_data->viewport) != RS::VIEWPORT_CASCADE_ALL : false; + if (step_cascades) { + // For stepped cascades each viewport needs its own atlas + light_storage->update_directional_shadow_atlas(p_render_data->viewport); + + // We don't insert an empty pass here as we're reusing data from previous frames + } else { + // Use our shared directional shadow atlas + light_storage->update_directional_shadow_atlas(); + + // inserting an empty pass here will clear our shadow map and enable us to run this in parallel with GI + RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_end(); + } } } @@ -1399,11 +1417,12 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo //render directional shadows for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info); + _render_shadow_pass(p_render_data->viewport, p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info, rb); } + //render positional shadows for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info); + _render_shadow_pass(p_render_data->viewport, p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info, rb); } _render_shadow_process(); @@ -1475,7 +1494,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo if (rb_data.is_valid()) { bool directional_shadows = RendererRD::LightStorage::get_singleton()->has_directional_shadows(directional_light_count); - _update_volumetric_fog(rb, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes); + _update_volumetric_fog(rb, p_render_data->viewport, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes); } } @@ -2086,7 +2105,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } if (rb_data.is_valid()) { - _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex); + _render_buffers_debug_draw(p_render_data); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) { Ref sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); @@ -2104,38 +2123,40 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } -void RenderForwardClustered::_render_buffers_debug_draw(Ref p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) { +void RenderForwardClustered::_render_buffers_debug_draw(RenderDataRD *p_render_data) { RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); - ERR_FAIL_COND(p_render_buffers.is_null()); - Ref rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); + Ref rb = p_render_data->render_buffers; + ERR_FAIL_COND(rb.is_null()); + + Ref rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED); ERR_FAIL_COND(rb_data.is_null()); - RendererSceneRenderRD::_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occlusion_buffer); + RendererSceneRenderRD::_render_buffers_debug_draw(p_render_data); - RID render_target = p_render_buffers->get_render_target(); + RID render_target = rb->get_render_target(); - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSAO && p_render_buffers->has_texture(RB_SCOPE_SSAO, RB_FINAL)) { - RID final = p_render_buffers->get_texture_slice(RB_SCOPE_SSAO, RB_FINAL, 0, 0); + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->has_texture(RB_SCOPE_SSAO, RB_FINAL)) { + RID final = rb->get_texture_slice(RB_SCOPE_SSAO, RB_FINAL, 0, 0); Size2i rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, true); } - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSIL && p_render_buffers->has_texture(RB_SCOPE_SSIL, RB_FINAL)) { - RID final = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_FINAL, 0, 0); + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSIL && rb->has_texture(RB_SCOPE_SSIL, RB_FINAL)) { + RID final = rb->get_texture_slice(RB_SCOPE_SSIL, RB_FINAL, 0, 0); Size2i rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); } - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && p_render_buffers->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) { + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) { Size2i rtsize = texture_storage->render_target_get_size(render_target); - RID ambient_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT); - RID reflection_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION); - copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, p_render_buffers->get_view_count() > 1); + RID ambient_texture = rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT); + RID reflection_texture = rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION); + copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, rb->get_view_count() > 1); } } -void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info) { +void RenderForwardClustered::_render_shadow_pass(RID p_viewport, RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info, Ref p_render_buffers) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); @@ -2172,8 +2193,8 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas } use_pancake = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0; - light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass); - light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass); + light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass, p_viewport); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass, p_viewport); atlas_rect = light_storage->light_instance_get_directional_rect(p_light); @@ -2201,14 +2222,24 @@ void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas Rect2 atlas_rect_norm = atlas_rect; atlas_rect_norm.position /= directional_shadow_size; atlas_rect_norm.size /= directional_shadow_size; - light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect_norm); + light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect_norm, p_viewport); zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE); - render_fb = light_storage->direction_shadow_get_fb(); + bool step_cascades = p_viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_viewport) != RS::VIEWPORT_CASCADE_ALL : false; + if (step_cascades) { + // Clear each region as we render it + p_open_pass = p_pass == 0; + p_clear_region = true; + + // Use the shadow map we created for our viewport + render_fb = light_storage->direction_shadow_get_fb(p_viewport); + } else { + // Use our shared shadow map + render_fb = light_storage->direction_shadow_get_fb(); + } render_texture = RID(); flip_y = true; - } else { //set from shadow atlas @@ -2946,7 +2977,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; if (p_render_data && p_render_data->shadow_atlas.is_valid()) { - texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_render_data->shadow_atlas); + texture = light_storage->shadow_atlas_get_texture(p_render_data->shadow_atlas); } if (!texture.is_valid()) { texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH); @@ -2958,8 +2989,18 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend RD::Uniform u; u.binding = 6; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - if (p_use_directional_shadow_atlas && RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture().is_valid()) { - u.append_id(RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture()); + + RID direction_shadow_texture; + if (p_use_directional_shadow_atlas) { + bool step_cascades = p_render_data->viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_render_data->viewport) != RS::VIEWPORT_CASCADE_ALL : false; + if (step_cascades) { + direction_shadow_texture = light_storage->directional_shadow_get_texture(p_render_data->viewport); + } else { + direction_shadow_texture = light_storage->directional_shadow_get_texture(); + } + } + if (direction_shadow_texture.is_valid()) { + u.append_id(direction_shadow_texture); } else { u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH)); } diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index e07d2f2258bb..adec29154d23 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -581,11 +581,11 @@ class RenderForwardClustered : public RendererSceneRenderRD { /* Volumetric fog */ RID shadow_sampler; - void _update_volumetric_fog(Ref p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes); + void _update_volumetric_fog(Ref p_render_buffers, RID p_viewport, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray &p_fog_volumes); /* Render shadows */ - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_pass(RID p_viewport, RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info, Ref p_render_buffers); void _render_shadow_begin(); void _render_shadow_append(RID p_framebuffer, const PagedArray &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr); void _render_shadow_process(); @@ -618,7 +618,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { /* Rendering */ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; - virtual void _render_buffers_debug_draw(Ref p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) override; + virtual void _render_buffers_debug_draw(RenderDataRD *p_render_data) override; virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override; virtual void _render_uv2(const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) override; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index b9edc46aeee9..53aaff3a4656 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -435,8 +435,18 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ RD::Uniform u; u.binding = 5; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - if (p_use_directional_shadow_atlas && light_storage->directional_shadow_get_texture().is_valid()) { - u.append_id(light_storage->directional_shadow_get_texture()); + + RID direction_shadow_texture; + if (p_use_directional_shadow_atlas) { + bool step_cascades = p_render_data->viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_render_data->viewport) != RS::VIEWPORT_CASCADE_ALL : false; + if (step_cascades) { + direction_shadow_texture = light_storage->directional_shadow_get_texture(p_render_data->viewport); + } else { + direction_shadow_texture = light_storage->directional_shadow_get_texture(); + } + } + if (direction_shadow_texture.is_valid()) { + u.append_id(direction_shadow_texture); } else { u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH)); } @@ -575,6 +585,8 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); + Ref rb = p_render_data->render_buffers; + p_render_data->cube_shadows.clear(); p_render_data->shadows.clear(); p_render_data->directional_shadows.clear(); @@ -597,14 +609,18 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { //cube shadows are rendered in their own way for (const int &index : p_render_data->cube_shadows) { - _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info); + _render_shadow_pass(p_render_data->viewport, p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, p_render_data->render_info, rb); } if (p_render_data->directional_shadows.size()) { - //open the pass for directional shadows - light_storage->update_directional_shadow_atlas(); - RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE); - RD::get_singleton()->draw_list_end(); + bool step_cascades = p_render_data->viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_render_data->viewport) != RS::VIEWPORT_CASCADE_ALL : false; + if (step_cascades) { + // For stepped cascades each viewport needs its own atlas + light_storage->update_directional_shadow_atlas(p_render_data->viewport); + } else { + // Use our shared directional shadow atlas + light_storage->update_directional_shadow_atlas(); + } } } @@ -618,11 +634,11 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { //render directional shadows for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info); + _render_shadow_pass(p_render_data->viewport, p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, p_render_data->render_info, rb); } //render positional shadows for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) { - _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info); + _render_shadow_pass(p_render_data->viewport, p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, p_render_data->render_info, rb); } _render_shadow_process(); @@ -1083,12 +1099,12 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color _disable_clear_request(p_render_data); } - _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex); + _render_buffers_debug_draw(p_render_data); } /* these are being called from RendererSceneRenderRD::_pre_opaque_render */ -void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info) { +void RenderForwardMobile::_render_shadow_pass(RID p_viewport, RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, RenderingMethod::RenderInfo *p_render_info, Ref p_render_buffers) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); ERR_FAIL_COND(!light_storage->owns_light_instance(p_light)); @@ -1125,8 +1141,8 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i } use_pancake = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0; - light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass); - light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass); + light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass, p_viewport); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass, p_viewport); atlas_rect = light_storage->light_instance_get_directional_rect(p_light); @@ -1154,11 +1170,21 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i Rect2 atlas_rect_norm = atlas_rect; atlas_rect_norm.position /= directional_shadow_size; atlas_rect_norm.size /= directional_shadow_size; - light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect_norm); + light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect_norm, p_viewport); zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE); - render_fb = light_storage->direction_shadow_get_fb(); + bool step_cascades = p_viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_viewport) != RS::VIEWPORT_CASCADE_ALL : false; + if (step_cascades) { + // Clear each region as we render it + p_open_pass = p_pass == 0; + + // Use the shadow map we created for our viewport + render_fb = light_storage->direction_shadow_get_fb(p_viewport); + } else { + // Use our shared shadow map + render_fb = light_storage->direction_shadow_get_fb(); + } render_texture = RID(); flip_y = true; @@ -1260,7 +1286,7 @@ void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, i } else { //render shadow - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, true, p_open_pass, p_close_pass, p_render_info); } } diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 214b39c49666..d2235ed1eb80 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -192,7 +192,7 @@ class RenderForwardMobile : public RendererSceneRenderRD { /* Render shadows */ - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_shadow_pass(RID p_viewport, RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, RenderingMethod::RenderInfo *p_render_info, Ref p_render_buffers); void _render_shadow_begin(); void _render_shadow_append(RID p_framebuffer, const PagedArray &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr); void _render_shadow_process(); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index efd961fd8992..3868124d8237 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -659,16 +659,17 @@ void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_ texture_storage->render_target_disable_clear_request(p_render_data->render_buffers->get_render_target()); } -void RendererSceneRenderRD::_render_buffers_debug_draw(Ref p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) { +void RendererSceneRenderRD::_render_buffers_debug_draw(RenderDataRD *p_render_data) { RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); - ERR_FAIL_COND(p_render_buffers.is_null()); + Ref rb = p_render_data->render_buffers; + ERR_FAIL_COND(rb.is_null()); - RID render_target = p_render_buffers->get_render_target(); + RID render_target = rb->get_render_target(); if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) { - if (p_shadow_atlas.is_valid()) { - RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_shadow_atlas); + if (p_render_data->shadow_atlas.is_valid()) { + RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_render_data->shadow_atlas); if (shadow_atlas_texture.is_null()) { shadow_atlas_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK); @@ -680,8 +681,16 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) { - if (RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture().is_valid()) { - RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture(); + RID shadow_atlas_texture; + + bool step_cascades = p_render_data->viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_render_data->viewport) != RS::VIEWPORT_CASCADE_ALL : false; + if (step_cascades) { + shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture(p_render_data->viewport); + } else { + shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture(); + } + + if (shadow_atlas_texture.is_valid()) { Size2i rtsize = texture_storage->render_target_get_size(render_target); copy_effects->copy_to_fb_rect(shadow_atlas_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, true); @@ -699,7 +708,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) { - RID luminance_texture = luminance->get_current_luminance_buffer(p_render_buffers); + RID luminance_texture = luminance->get_current_luminance_buffer(rb); if (luminance_texture.is_valid()) { Size2i rtsize = texture_storage->render_target_get_size(render_target); @@ -707,21 +716,21 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref } } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(rb).is_valid()) { Size2 rtsize = texture_storage->render_target_get_size(render_target); - copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); + copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) { - if (p_occlusion_buffer.is_valid()) { + if (p_render_data->occluder_debug_tex.is_valid()) { Size2i rtsize = texture_storage->render_target_get_size(render_target); - copy_effects->copy_to_fb_rect(texture_storage->texture_get_rd_texture(p_occlusion_buffer), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize), true, false); + copy_effects->copy_to_fb_rect(texture_storage->texture_get_rd_texture(p_render_data->occluder_debug_tex), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize), true, false); } } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(p_render_buffers).is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(rb).is_valid()) { Size2i rtsize = texture_storage->render_target_get_size(render_target); - copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); + copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false); } } @@ -927,7 +936,7 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo } } -void RendererSceneRenderRD::render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) { +void RendererSceneRenderRD::render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_viewport, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); @@ -1000,6 +1009,7 @@ void RendererSceneRenderRD::render_scene(const Ref &p_render render_data.decals = &p_decals; render_data.lightmaps = &p_lightmaps; render_data.fog_volumes = &p_fog_volumes; + render_data.viewport = p_viewport; render_data.environment = p_environment; render_data.camera_attributes = p_camera_attributes; render_data.shadow_atlas = p_shadow_atlas; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 7c43021eb058..6ac382bd65e8 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -65,6 +65,7 @@ struct RenderDataRD { const PagedArray *decals = nullptr; const PagedArray *lightmaps = nullptr; const PagedArray *fog_volumes = nullptr; + RID viewport; RID environment; RID camera_attributes; RID shadow_atlas; @@ -128,7 +129,7 @@ class RendererSceneRenderRD : public RendererSceneRender { virtual void setup_render_buffer_data(Ref p_render_buffers) = 0; virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0; - virtual void _render_buffers_debug_draw(Ref p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer); + virtual void _render_buffers_debug_draw(RenderDataRD *p_render_data); virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) = 0; virtual void _render_uv2(const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; @@ -280,7 +281,7 @@ class RendererSceneRenderRD : public RendererSceneRender { virtual void base_uniforms_changed() = 0; virtual void update_uniform_sets(){}; - virtual void render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override; + virtual void render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_viewport, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override; virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) override; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index e65d842a677a..10eec226fcf6 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -70,6 +70,7 @@ LightStorage::LightStorage() { LightStorage::~LightStorage() { free_reflection_data(); free_light_data(); + free_directional_shadows(); for (const KeyValue &E : shadow_cubemaps) { RD::get_singleton()->free(E.value.cubemap); @@ -483,20 +484,33 @@ void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_a light_instance->aabb = p_aabb; } -void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { +void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale, RID p_viewport) { LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); ERR_FAIL_COND(!light_instance); - ERR_FAIL_INDEX(p_pass, 6); + if (p_viewport.is_valid()) { + ERR_FAIL_INDEX(p_pass, 4); + + light_instance->shadow_viewport[p_viewport].pass[p_pass].camera = p_projection; + light_instance->shadow_viewport[p_viewport].pass[p_pass].transform = p_transform; + light_instance->shadow_viewport[p_viewport].pass[p_pass].farplane = p_far; + light_instance->shadow_viewport[p_viewport].pass[p_pass].split = p_split; + light_instance->shadow_viewport[p_viewport].pass[p_pass].bias_scale = p_bias_scale; + light_instance->shadow_viewport[p_viewport].pass[p_pass].range_begin = p_range_begin; + light_instance->shadow_viewport[p_viewport].pass[p_pass].shadow_texel_size = p_shadow_texel_size; + light_instance->shadow_viewport[p_viewport].pass[p_pass].uv_scale = p_uv_scale; + } else { + ERR_FAIL_INDEX(p_pass, 6); - light_instance->shadow_transform[p_pass].camera = p_projection; - light_instance->shadow_transform[p_pass].transform = p_transform; - light_instance->shadow_transform[p_pass].farplane = p_far; - light_instance->shadow_transform[p_pass].split = p_split; - light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; - light_instance->shadow_transform[p_pass].range_begin = p_range_begin; - light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size; - light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale; + light_instance->shadow_transform[p_pass].camera = p_projection; + light_instance->shadow_transform[p_pass].transform = p_transform; + light_instance->shadow_transform[p_pass].farplane = p_far; + light_instance->shadow_transform[p_pass].split = p_split; + light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; + light_instance->shadow_transform[p_pass].range_begin = p_range_begin; + light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size; + light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale; + } } void LightStorage::light_instance_mark_visible(RID p_light_instance) { @@ -671,28 +685,38 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3); light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light->directional_blend_splits; for (int j = 0; j < 4; j++) { - Rect2 atlas_rect = light_instance->shadow_transform[j].atlas_rect; - Projection matrix = light_instance->shadow_transform[j].camera; - float split = light_instance->shadow_transform[MIN(limit, j)].split; + float split; + + LightInstance::ShadowTransform *shadow_transform; + + if (p_render_data->viewport.is_valid()) { + shadow_transform = &light_instance->shadow_viewport[p_render_data->viewport].pass[j]; + split = light_instance->shadow_viewport[p_render_data->viewport].pass[MIN(limit, j)].split; + } else { + shadow_transform = &light_instance->shadow_transform[j]; + split = light_instance->shadow_transform[MIN(limit, j)].split; + } + + Rect2 atlas_rect = shadow_transform->atlas_rect; + Projection matrix = shadow_transform->camera; + Transform3D modelview = (inverse_transform * shadow_transform->transform).inverse(); Projection bias; bias.set_light_bias(); Projection rectm; rectm.set_light_atlas_rect(atlas_rect); - Transform3D modelview = (inverse_transform * light_instance->shadow_transform[j].transform).inverse(); - Projection shadow_mtx = rectm * bias * matrix * modelview; light_data.shadow_split_offsets[j] = split; - float bias_scale = light_instance->shadow_transform[j].bias_scale * light_data.soft_shadow_scale; + float bias_scale = shadow_transform->bias_scale * light_data.soft_shadow_scale; light_data.shadow_bias[j] = light->param[RS::LIGHT_PARAM_SHADOW_BIAS] / 100.0 * bias_scale; - light_data.shadow_normal_bias[j] = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * light_instance->shadow_transform[j].shadow_texel_size; + light_data.shadow_normal_bias[j] = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * shadow_transform->shadow_texel_size; light_data.shadow_transmittance_bias[j] = light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] * bias_scale; - light_data.shadow_z_range[j] = light_instance->shadow_transform[j].farplane; - light_data.shadow_range_begin[j] = light_instance->shadow_transform[j].range_begin; + light_data.shadow_z_range[j] = shadow_transform->farplane; + light_data.shadow_range_begin[j] = shadow_transform->range_begin; RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrices[j]); - Vector2 uv_scale = light_instance->shadow_transform[j].uv_scale; + Vector2 uv_scale = shadow_transform->uv_scale; uv_scale *= atlas_rect.size; //adapt to atlas size switch (j) { case 0: { @@ -1012,6 +1036,28 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged } } +void LightStorage::cleanup_directional_shadow_viewport(RID p_viewport) { + List owned; + light_instance_owner.get_owned_list(&owned); + + for (RID &rid : owned) { + LightInstance *light_instance = light_instance_owner.get_or_null(rid); + if (light_instance) { + if (light_instance->shadow_viewport.has(p_viewport)) { + light_instance->shadow_viewport.erase(p_viewport); + } + } + } + + if (directional_shadow_vp.has(p_viewport)) { + if (directional_shadow_vp[p_viewport].depth.is_valid()) { + RD::get_singleton()->free(directional_shadow_vp[p_viewport].depth); + } + + directional_shadow_vp.erase(p_viewport); + } +} + /* REFLECTION PROBE */ RID LightStorage::reflection_probe_allocate() { @@ -2352,8 +2398,25 @@ void LightStorage::shadow_atlas_update(RID p_atlas) { /* DIRECTIONAL SHADOW */ -void LightStorage::update_directional_shadow_atlas() { - if (directional_shadow.depth.is_null() && directional_shadow.size > 0) { +void LightStorage::update_directional_shadow_atlas(RID p_viewport) { + if (p_viewport.is_valid()) { + if (!directional_shadow_vp.has(p_viewport)) { + DirectionalShadowVP dsvp; + + RD::TextureFormat tf; + tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; + tf.width = directional_shadow.size; + tf.height = directional_shadow.size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + dsvp.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector fb_tex; + fb_tex.push_back(dsvp.depth); + dsvp.fb = RD::get_singleton()->framebuffer_create(fb_tex); + + directional_shadow_vp[p_viewport] = dsvp; + } + } else if (directional_shadow.depth.is_null() && directional_shadow.size > 0) { RD::TextureFormat tf; tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; tf.width = directional_shadow.size; @@ -2366,6 +2429,28 @@ void LightStorage::update_directional_shadow_atlas() { directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb_tex); } } + +bool LightStorage::free_directional_shadows() { + bool freed_something = false; + + if (directional_shadow.depth.is_valid()) { + RD::get_singleton()->free(directional_shadow.depth); + directional_shadow.depth = RID(); + + freed_something = true; + } + + for (KeyValue &key : directional_shadow_vp) { + if (key.value.depth.is_valid()) { + RD::get_singleton()->free(key.value.depth); + freed_something = true; + } + } + directional_shadow_vp.clear(); + + return freed_something; +} + void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { p_size = nearest_power_of_2_templated(p_size); @@ -2376,9 +2461,7 @@ void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) directional_shadow.size = p_size; directional_shadow.use_16_bits = p_16_bits; - if (directional_shadow.depth.is_valid()) { - RD::get_singleton()->free(directional_shadow.depth); - directional_shadow.depth = RID(); + if (free_directional_shadows()) { RendererSceneRenderRD::get_singleton()->base_uniforms_changed(); } } diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index c36d1ef503ba..f2e0a8308cfc 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -106,6 +106,12 @@ class LightStorage : public RendererLightStorage { ShadowTransform shadow_transform[6]; + /* For stepped updates of directional lights, we need to store this per viewport */ + struct ShadowTransformPass { + ShadowTransform pass[4]; + }; + mutable HashMap shadow_viewport; + AABB aabb; RID self; RID light; @@ -414,15 +420,30 @@ class LightStorage : public RendererLightStorage { /* DIRECTIONAL SHADOW */ struct DirectionalShadow { - RID depth; - RID fb; //when renderign direct - - int light_count = 0; + // settings int size = 0; bool use_16_bits = true; + bool step_cascades = false; + + // Our shared shadow map + RID depth; + RID fb; // when rendering direct + int current_light = 0; + int light_count = 0; } directional_shadow; + // To enabled stepped cascade updates, we need a separate shadow map per viewport + struct DirectionalShadowVP { + RID depth; + RID fb; // when rendering direct + + bool needs_full_update = true; + }; + + HashMap directional_shadow_vp; + bool free_directional_shadows(); + /* SHADOW CUBEMAPS */ struct ShadowCubemap { @@ -580,7 +601,7 @@ class LightStorage : public RendererLightStorage { virtual void light_instance_free(RID p_light) override; virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2(), RID p_viewport = RID()) override; virtual void light_instance_mark_visible(RID p_light_instance) override; _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { @@ -665,52 +686,109 @@ class LightStorage : public RendererLightStorage { return float(1.0) / shadow_size; } - _FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) { + _FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index, RID p_viewport = RID()) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].camera; + ERR_FAIL_NULL_V(li, Projection()); + if (p_viewport.is_valid()) { + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), Projection()); + ERR_FAIL_INDEX_V(p_index, 4, Projection()); + return li->shadow_viewport[p_viewport].pass[p_index].camera; + } else { + return li->shadow_transform[p_index].camera; + } } _FORCE_INLINE_ Transform3D - light_instance_get_shadow_transform(RID p_light_instance, int p_index) { + light_instance_get_shadow_transform(RID p_light_instance, int p_index, RID p_viewport = RID()) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].transform; + ERR_FAIL_NULL_V(li, Transform3D()); + if (p_viewport.is_valid()) { + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), Transform3D()); + ERR_FAIL_INDEX_V(p_index, 4, Transform3D()); + return li->shadow_viewport[p_viewport].pass[p_index].transform; + } else { + return li->shadow_transform[p_index].transform; + } } - _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) { + _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index, RID p_viewport = RID()) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].bias_scale; + ERR_FAIL_NULL_V(li, 0.0); + if (p_viewport.is_valid()) { + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), 0.0); + ERR_FAIL_INDEX_V(p_index, 4, 0.0); + return li->shadow_viewport[p_viewport].pass[p_index].bias_scale; + } else { + return li->shadow_transform[p_index].bias_scale; + } } - _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) { + _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index, RID p_viewport = RID()) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].farplane; + ERR_FAIL_NULL_V(li, 0.0); + if (p_viewport.is_valid()) { + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), 0.0); + ERR_FAIL_INDEX_V(p_index, 4, 0.0); + return li->shadow_viewport[p_viewport].pass[p_index].farplane; + } else { + return li->shadow_transform[p_index].farplane; + } } - _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) { + _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index, RID p_viewport = RID()) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].range_begin; + ERR_FAIL_NULL_V(li, 0.0); + if (p_viewport.is_valid()) { + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), 0.0); + ERR_FAIL_INDEX_V(p_index, 4, 0.0); + return li->shadow_viewport[p_viewport].pass[p_index].range_begin; + } else { + return li->shadow_transform[p_index].range_begin; + } } - _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) { + _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index, RID p_viewport = RID()) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].uv_scale; + ERR_FAIL_NULL_V(li, Vector2()); + if (p_viewport.is_valid()) { + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), Vector2()); + ERR_FAIL_INDEX_V(p_index, 4, Vector2()); + return li->shadow_viewport[p_viewport].pass[p_index].uv_scale; + } else { + return li->shadow_transform[p_index].uv_scale; + } } - _FORCE_INLINE_ void light_instance_set_directional_shadow_atlas_rect(RID p_light_instance, int p_index, const Rect2 p_atlas_rect) { + _FORCE_INLINE_ void light_instance_set_directional_shadow_atlas_rect(RID p_light_instance, int p_index, const Rect2 p_atlas_rect, RID p_viewport) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - li->shadow_transform[p_index].atlas_rect = p_atlas_rect; + ERR_FAIL_NULL(li); + ERR_FAIL_INDEX(p_index, 4); + + li->shadow_viewport[p_viewport].pass[p_index].atlas_rect = p_atlas_rect; } - _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) { + _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index, RID p_viewport) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].atlas_rect; + ERR_FAIL_NULL_V(li, Rect2()); + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), Rect2()); + ERR_FAIL_INDEX_V(p_index, 4, Rect2()); + + return li->shadow_viewport[p_viewport].pass[p_index].atlas_rect; } - _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) { + _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index, RID p_viewport) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].split; + ERR_FAIL_NULL_V(li, 0.0); + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), 0.0); + ERR_FAIL_INDEX_V(p_index, 4, 0.0); + + return li->shadow_viewport[p_viewport].pass[p_index].split; } - _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) { + _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index, RID p_viewport) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); - return li->shadow_transform[p_index].shadow_texel_size; + ERR_FAIL_NULL_V(li, 0.0); + ERR_FAIL_COND_V(!li->shadow_viewport.has(p_viewport), 0.0); + ERR_FAIL_INDEX_V(p_index, 4, 0.0); + + return li->shadow_viewport[p_viewport].pass[p_index].shadow_texel_size; } _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) { @@ -1049,19 +1127,52 @@ class LightStorage : public RendererLightStorage { virtual int get_directional_light_shadow_size(RID p_light_intance) override; virtual void set_directional_shadow_count(int p_count) override; - Rect2i get_directional_shadow_rect(); - void update_directional_shadow_atlas(); + virtual bool directional_shadow_get_needs_full_update(RID p_viewport) const override { + if (directional_shadow_vp.has(p_viewport)) { + return directional_shadow_vp[p_viewport].needs_full_update; + } else { + // we haven't created a shadowmap (yet), then once we do we will need a full update + return true; + } + } - _FORCE_INLINE_ RID directional_shadow_get_texture() { - return directional_shadow.depth; + virtual void directional_shadow_set_needs_full_update(RID p_viewport, bool p_needs_update) override { + // We only need to set this if our shadowmap was previously created. + // A full update must be triggered so we can ignore p_needs_update. + if (directional_shadow_vp.has(p_viewport)) { + directional_shadow_vp[p_viewport].needs_full_update = p_needs_update; + } + } + + virtual void cleanup_directional_shadow_viewport(RID p_viewport) override; + + Rect2i get_directional_shadow_rect(); + void update_directional_shadow_atlas(RID p_viewport = RID()); + + _FORCE_INLINE_ RID directional_shadow_get_texture(RID p_viewport = RID()) { + if (p_viewport.is_valid()) { + ERR_FAIL_COND_V(!directional_shadow_vp.has(p_viewport), RID()); + return directional_shadow_vp[p_viewport].depth; + } else { + return directional_shadow.depth; + } } _FORCE_INLINE_ int directional_shadow_get_size() { return directional_shadow.size; } - _FORCE_INLINE_ RID direction_shadow_get_fb() { - return directional_shadow.fb; + _FORCE_INLINE_ bool directional_shadow_use_16_bits() { + return directional_shadow.use_16_bits; + } + + _FORCE_INLINE_ RID direction_shadow_get_fb(RID p_viewport = RID()) { + if (p_viewport.is_valid()) { + ERR_FAIL_COND_V(!directional_shadow_vp.has(p_viewport), RID()); + return directional_shadow_vp[p_viewport].fb; + } else { + return directional_shadow.fb; + } } _FORCE_INLINE_ void directional_shadow_increase_current_light() { diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 6a872da69eeb..24182422e5e5 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -3143,21 +3143,64 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c // Directional Shadows + int viewports_pass = RSG::viewport->get_draw_viewports_pass(); // this is increases for every frame we draw + RS::ViewportCascadeMode cascade_mode = p_viewport.is_valid() ? RSG::viewport->viewport_get_cascade_mode(p_viewport) : RS::VIEWPORT_CASCADE_ALL; + bool needs_full_update = RSG::light_storage->directional_shadow_get_needs_full_update(p_viewport); + for (uint32_t i = 0; i < cull.shadow_count; i++) { for (uint32_t j = 0; j < cull.shadows[i].cascade_count; j++) { - const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j]; - // print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size())); - RSG::light_storage->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale); - if (max_shadows_used == MAX_UPDATE_SHADOWS) { - continue; + bool skip = false; + if (cascade_mode == RS::VIEWPORT_CASCADE_TWOSTEP && !needs_full_update && cull.shadows[i].cascade_count == 4) { + // We only render 3 cascades per frame (pass) + // 0: 0 + 1 + 2 + // 1: 0 + 1 + 3 + // So cascade 0 and 1 are always renderered + // And cascades 2 and 3 are rendered overy other frame + + if (j == 2 && (viewports_pass % 2) != 0) { + skip = true; + } else if (j == 3 && (viewports_pass % 2) != 1) { + skip = true; + } + } else if (cascade_mode == RS::VIEWPORT_CASCADE_FOURSTEP && !needs_full_update && cull.shadows[i].cascade_count == 4) { + // We only render 2 cascades per frame (pass) + // 0: 0 + 1 + // 1: 0 + 2 + // 2: 0 + 1 + // 3: 0 + 3 + // So cascade 0 is always renderered + // Cascade 1 is rendered every other frame + // And cascades 2 and 3 are rendered once every 4 frames + + if (j == 1 && (viewports_pass % 2) != 0) { + skip = true; + } else if (j == 2 && (viewports_pass % 4) != 1) { + skip = true; + } else if (j == 3 && (viewports_pass % 4) != 3) { + skip = true; + } + } + + if (!skip) { + const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j]; + // print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size())); + RSG::light_storage->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale, p_viewport); + if (max_shadows_used == MAX_UPDATE_SHADOWS) { + continue; + } + render_shadow_data[max_shadows_used].light = cull.shadows[i].light_instance; + render_shadow_data[max_shadows_used].pass = j; + render_shadow_data[max_shadows_used].instances.merge_unordered(scene_cull_result.directional_shadows[i].cascade_geometry_instances[j]); + max_shadows_used++; } - render_shadow_data[max_shadows_used].light = cull.shadows[i].light_instance; - render_shadow_data[max_shadows_used].pass = j; - render_shadow_data[max_shadows_used].instances.merge_unordered(scene_cull_result.directional_shadows[i].cascade_geometry_instances[j]); - max_shadows_used++; } } + if (cascade_mode != RS::VIEWPORT_CASCADE_ALL && needs_full_update) { + // Don't need to do this next frame.. + RSG::light_storage->directional_shadow_set_needs_full_update(p_viewport, false); + } + // Positional Shadowss for (uint32_t i = 0; i < (uint32_t)scene_cull_result.lights.size(); i++) { Instance *ins = scene_cull_result.lights[i]; @@ -3314,7 +3357,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c } RENDER_TIMESTAMP("Render 3D Scene"); - scene_render->render_scene(p_render_buffers, p_camera_data, prev_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, scene_cull_result.fog_volumes, p_environment, camera_attributes, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_mesh_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info); + scene_render->render_scene(p_render_buffers, p_camera_data, prev_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, scene_cull_result.fog_volumes, p_environment, camera_attributes, p_shadow_atlas, occluders_tex, p_viewport, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_mesh_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info); if (p_viewport.is_valid()) { RSG::viewport->viewport_set_prev_camera_data(p_viewport, p_camera_data); @@ -3366,7 +3409,7 @@ void RendererSceneCull::render_empty_scene(const Ref &p_rend RendererSceneRender::CameraData camera_data; camera_data.set_camera(Transform3D(), Projection(), true, false); - scene_render->render_scene(p_render_buffers, &camera_data, &camera_data, PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), environment, RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); + scene_render->render_scene(p_render_buffers, &camera_data, &camera_data, PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), environment, RID(), p_shadow_atlas, RID(), RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); #endif } diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 900738364194..519144856825 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -282,7 +282,7 @@ class RendererSceneRender { void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect); }; - virtual void render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0; + virtual void render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_viewport, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0; virtual void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray &p_instances) = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index f609fa6023eb..05bfb5cd5b63 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -208,6 +208,10 @@ void RendererViewport::_draw_3d(Viewport *p_viewport) { } } + if (p_viewport->update_mode == RenderingServer::VIEWPORT_UPDATE_ONCE) { + RSG::light_storage->directional_shadow_set_needs_full_update(p_viewport->self, true); + } + float screen_mesh_lod_threshold = p_viewport->mesh_lod_threshold / float(p_viewport->size.width); RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->internal_size, p_viewport->use_taa, screen_mesh_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info); @@ -1326,10 +1330,25 @@ void RendererViewport::viewport_set_vrs_texture(RID p_viewport, RID p_texture) { _configure_3d_render_buffers(viewport); } +void RendererViewport::viewport_set_cascade_mode(RID p_viewport, RS::ViewportCascadeMode p_mode) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->cascade_mode = p_mode; +} + +RS::ViewportCascadeMode RendererViewport::viewport_get_cascade_mode(RID p_viewport) const { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND_V(!viewport, RS::VIEWPORT_CASCADE_ALL); + + return viewport->cascade_mode; +} + bool RendererViewport::free(RID p_rid) { if (viewport_owner.owns(p_rid)) { Viewport *viewport = viewport_owner.get_or_null(p_rid); + RSG::light_storage->cleanup_directional_shadow_viewport(p_rid); RSG::texture_storage->render_target_free(viewport->render_target); RSG::light_storage->shadow_atlas_free(viewport->shadow_atlas); if (viewport->render_buffers.is_valid()) { diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index c24275de6e63..4b830ed9c305 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -101,6 +101,7 @@ class RendererViewport { RID shadow_atlas; int shadow_atlas_size = 2048; bool shadow_atlas_16_bits = true; + RS::ViewportCascadeMode cascade_mode = RS::VIEWPORT_CASCADE_ALL; bool sdf_active = false; @@ -288,10 +289,14 @@ class RendererViewport { void viewport_set_vrs_mode(RID p_viewport, RS::ViewportVRSMode p_mode); void viewport_set_vrs_texture(RID p_viewport, RID p_texture); + void viewport_set_cascade_mode(RID p_viewport, RS::ViewportCascadeMode p_mode); + RS::ViewportCascadeMode viewport_get_cascade_mode(RID p_viewport) const; + void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time); void set_default_clear_color(const Color &p_color); void draw_viewports(); + uint64_t get_draw_viewports_pass() { return draw_viewports_pass; } bool free(RID p_rid); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 249e5c2d9dfb..861882475d45 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -655,6 +655,9 @@ class RenderingServerDefault : public RenderingServer { FUNC2(viewport_set_vrs_mode, RID, ViewportVRSMode) FUNC2(viewport_set_vrs_texture, RID, RID) + FUNC2(viewport_set_cascade_mode, RID, ViewportCascadeMode) + FUNC1RC(ViewportCascadeMode, viewport_get_cascade_mode, RID) + /* ENVIRONMENT API */ #undef server_name diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h index 5bd429717952..826335e30401 100644 --- a/servers/rendering/storage/light_storage.h +++ b/servers/rendering/storage/light_storage.h @@ -92,7 +92,7 @@ class RendererLightStorage { virtual void light_instance_free(RID p_light_instance) = 0; virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) = 0; virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2(), RID p_viewport = RID()) = 0; virtual void light_instance_mark_visible(RID p_light_instance) = 0; virtual bool light_instances_can_render_shadow_cube() const { return true; @@ -188,6 +188,11 @@ class RendererLightStorage { virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0; virtual int get_directional_light_shadow_size(RID p_light_intance) = 0; virtual void set_directional_shadow_count(int p_count) = 0; + + virtual bool directional_shadow_get_needs_full_update(RID p_viewport) const = 0; + virtual void directional_shadow_set_needs_full_update(RID p_viewport, bool p_needs_update) = 0; + + virtual void cleanup_directional_shadow_viewport(RID p_viewport) = 0; }; #endif // LIGHT_STORAGE_H diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index cc09825298a7..efc03214e7ac 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2242,6 +2242,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_vrs_mode", "viewport", "mode"), &RenderingServer::viewport_set_vrs_mode); ClassDB::bind_method(D_METHOD("viewport_set_vrs_texture", "viewport", "texture"), &RenderingServer::viewport_set_vrs_texture); + ClassDB::bind_method(D_METHOD("viewport_set_cascade_mode", "viewport", "mode"), &RenderingServer::viewport_set_cascade_mode); + ClassDB::bind_method(D_METHOD("viewport_get_cascade_mode", "viewport"), &RenderingServer::viewport_get_cascade_mode); + BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_BILINEAR); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_MAX); @@ -2327,6 +2330,11 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_VRS_XR); BIND_ENUM_CONSTANT(VIEWPORT_VRS_MAX); + BIND_ENUM_CONSTANT(VIEWPORT_CASCADE_ALL); + BIND_ENUM_CONSTANT(VIEWPORT_CASCADE_TWOSTEP); + BIND_ENUM_CONSTANT(VIEWPORT_CASCADE_FOURSTEP); + BIND_ENUM_CONSTANT(VIEWPORT_CASCADE_MAX); + /* SKY API */ ClassDB::bind_method(D_METHOD("sky_create"), &RenderingServer::sky_create); @@ -2873,6 +2881,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"), 2); GLOBAL_DEF("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality.mobile", 0); GLOBAL_DEF("rendering/lights_and_shadows/directional_shadow/16_bits", true); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lights_and_shadows/directional_shadow/step_cascades", PROPERTY_HINT_ENUM, "All (Slowest),Two step (Faster),Four step (Fastest)"), 0); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"), 2); GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality.mobile", 0); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index a28374444386..b231e129b2e3 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -983,6 +983,16 @@ class RenderingServer : public Object { virtual void viewport_set_vrs_mode(RID p_viewport, ViewportVRSMode p_mode) = 0; virtual void viewport_set_vrs_texture(RID p_viewport, RID p_texture) = 0; + enum ViewportCascadeMode { + VIEWPORT_CASCADE_ALL, + VIEWPORT_CASCADE_TWOSTEP, + VIEWPORT_CASCADE_FOURSTEP, + VIEWPORT_CASCADE_MAX + }; + + virtual void viewport_set_cascade_mode(RID p_viewport, ViewportCascadeMode p_mode) = 0; + virtual ViewportCascadeMode viewport_get_cascade_mode(RID p_viewport) const = 0; + /* SKY API */ enum SkyMode { @@ -1655,6 +1665,7 @@ VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality); VARIANT_ENUM_CAST(RenderingServer::ViewportSDFOversize); VARIANT_ENUM_CAST(RenderingServer::ViewportSDFScale); VARIANT_ENUM_CAST(RenderingServer::ViewportVRSMode); +VARIANT_ENUM_CAST(RenderingServer::ViewportCascadeMode); VARIANT_ENUM_CAST(RenderingServer::SkyMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG); VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource);