summaryrefslogtreecommitdiff
path: root/servers/rendering/renderer_rd/forward_clustered
diff options
context:
space:
mode:
authorBastiaan Olij <mux213@gmail.com>2022-09-12 19:44:48 +1000
committerBastiaan Olij <mux213@gmail.com>2022-10-04 11:03:32 +1100
commitddc4ae117595e2059404170ff3e8c6040413b219 (patch)
tree2c4b14075af62948dae024238a143f8a4beb14a6 /servers/rendering/renderer_rd/forward_clustered
parent4b52c6caef8a9e5d940ce0977d5c467296ac5805 (diff)
Move cluster builder, sdfgi and gi structures to clustered renderer, move light and probe elements into storage and reorganise our render_scene method.
Diffstat (limited to 'servers/rendering/renderer_rd/forward_clustered')
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp829
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h82
2 files changed, 876 insertions, 35 deletions
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 3a9c695653..4fc4ba40bd 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -110,9 +110,29 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::free_data() {
render_buffers->clear_context(RB_SCOPE_FORWARD_CLUSTERED);
}
+ if (cluster_builder) {
+ memdelete(cluster_builder);
+ cluster_builder = nullptr;
+ }
+
if (!render_sdfgi_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_sdfgi_uniform_set)) {
RD::get_singleton()->free(render_sdfgi_uniform_set);
}
+
+ if (ss_effects_data.linear_depth.is_valid()) {
+ RD::get_singleton()->free(ss_effects_data.linear_depth);
+ ss_effects_data.linear_depth = RID();
+ ss_effects_data.linear_depth_slices.clear();
+ }
+
+ if (ss_effects_data.downsample_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(ss_effects_data.downsample_uniform_set)) {
+ RD::get_singleton()->free(ss_effects_data.downsample_uniform_set);
+ ss_effects_data.downsample_uniform_set = RID();
+ }
+
+ RenderForwardClustered::get_singleton()->get_ss_effects()->ssao_free(ss_effects_data.ssao);
+ RenderForwardClustered::get_singleton()->get_ss_effects()->ssil_free(ss_effects_data.ssil);
+ RenderForwardClustered::get_singleton()->get_ss_effects()->ssr_free(ss_effects_data.ssr);
}
void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderSceneBuffersRD *p_render_buffers) {
@@ -146,6 +166,14 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderS
p_render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
}
+
+ if (cluster_builder == nullptr) {
+ cluster_builder = memnew(ClusterBuilderRD);
+ }
+ cluster_builder->set_shared(RenderForwardClustered::get_singleton()->get_cluster_builder_shared());
+
+ RID sampler = RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ cluster_builder->setup(p_render_buffers->get_internal_size(), p_render_buffers->get_max_cluster_elements(), p_render_buffers->get_depth_texture(), sampler, p_render_buffers->get_internal_texture());
}
RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_only_fb() {
@@ -580,9 +608,11 @@ void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_p
}
void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
- RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
+ RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
// May do this earlier in RenderSceneRenderRD::render_scene
if (p_index >= (int)scene_state.uniform_buffers.size()) {
@@ -1030,26 +1060,28 @@ void RenderForwardClustered::_setup_voxelgis(const PagedArray<RID> &p_voxelgis)
}
void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
if (i >= (int)scene_state.max_lightmaps) {
break;
}
- RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]);
+ RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]);
- Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
+ Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
to_lm = to_lm.inverse().transposed(); //will transform normals
RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
scene_state.lightmaps[i].exposure_normalization = 1.0;
if (p_render_data->camera_attributes.is_valid()) {
- float baked_exposure = RendererRD::LightStorage::get_singleton()->lightmap_get_baked_exposure_normalization(lightmap);
+ float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure;
}
scene_state.lightmap_ids[i] = p_lightmaps[i];
- scene_state.lightmap_has_sh[i] = RendererRD::LightStorage::get_singleton()->lightmap_uses_spherical_harmonics(lightmap);
+ scene_state.lightmap_has_sh[i] = light_storage->lightmap_uses_spherical_harmonics(lightmap);
scene_state.lightmaps_used++;
}
@@ -1058,7 +1090,466 @@ void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data,
}
}
+/* SDFGI */
+
+void RenderForwardClustered::_update_sdfgi(RenderDataRD *p_render_data) {
+ Ref<RenderSceneBuffersRD> rb;
+ if (p_render_data && p_render_data->render_buffers.is_valid()) {
+ rb = p_render_data->render_buffers;
+ }
+
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ float exposure_normalization = 1.0;
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+ for (int i = 0; i < p_render_data->render_sdfgi_region_count; i++) {
+ sdfgi->render_region(rb, p_render_data->render_sdfgi_regions[i].region, p_render_data->render_sdfgi_regions[i].instances, exposure_normalization);
+ }
+ if (p_render_data->sdfgi_update_data->update_static) {
+ sdfgi->render_static_lights(p_render_data, rb, p_render_data->sdfgi_update_data->static_cascade_count, p_render_data->sdfgi_update_data->static_cascade_indices, p_render_data->sdfgi_update_data->static_positional_lights);
+ }
+ }
+}
+
+/* Debug */
+
+void RenderForwardClustered::_debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) {
+ RS::ViewportDebugDraw dd = get_debug_draw_mode();
+
+ if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
+ ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX;
+ switch (dd) {
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS:
+ elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT;
+ break;
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS:
+ elem_type = ClusterBuilderRD::ELEMENT_TYPE_SPOT_LIGHT;
+ break;
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS:
+ elem_type = ClusterBuilderRD::ELEMENT_TYPE_DECAL;
+ break;
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES:
+ elem_type = ClusterBuilderRD::ELEMENT_TYPE_REFLECTION_PROBE;
+ break;
+ default: {
+ }
+ }
+ current_cluster_builder->debug(elem_type);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FOG SHADER
+
+void RenderForwardClustered::_update_volumetric_fog(Ref<RenderSceneBuffersRD> 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<RID> &p_fog_volumes) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+
+ ERR_FAIL_COND(!p_render_buffers->has_custom_data(RB_SCOPE_GI));
+ Ref<RendererRD::GI::RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI);
+
+ Ref<RendererRD::GI::SDFGI> sdfgi;
+ if (p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
+ sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI);
+ }
+
+ Size2i size = p_render_buffers->get_internal_size();
+ float ratio = float(size.x) / float((size.x + size.y) / 2);
+ uint32_t target_width = uint32_t(float(get_volumetric_fog_size()) * ratio);
+ uint32_t target_height = uint32_t(float(get_volumetric_fog_size()) / ratio);
+
+ if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
+ //validate
+ if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment) || fog->width != target_width || fog->height != target_height || fog->depth != get_volumetric_fog_depth()) {
+ p_render_buffers->set_custom_data(RB_SCOPE_FOG, Ref<RenderBufferCustomDataRD>());
+ }
+ }
+
+ if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment)) {
+ //no reason to enable or update, bye
+ return;
+ }
+
+ if (p_environment.is_valid() && environment_get_volumetric_fog_enabled(p_environment) && !p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ //required volumetric fog but not existing, create
+ Ref<RendererRD::Fog::VolumetricFog> fog;
+
+ fog.instantiate();
+ fog->init(Vector3i(target_width, target_height, get_volumetric_fog_depth()), sky.sky_shader.default_shader_rd);
+
+ p_render_buffers->set_custom_data(RB_SCOPE_FOG, fog);
+ }
+
+ if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
+
+ RendererRD::Fog::VolumetricFogSettings settings;
+ 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.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.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.vfog = fog;
+ settings.cluster_builder = rb_data->cluster_builder;
+ settings.rbgi = rbgi;
+ settings.sdfgi = sdfgi;
+ settings.env = p_environment;
+ settings.sky = &sky;
+ settings.gi = &gi;
+
+ RendererRD::Fog::get_singleton()->volumetric_fog_update(settings, p_cam_projection, p_cam_transform, p_prev_cam_inv_transform, p_shadow_atlas, p_directional_light_count, p_use_directional_shadows, p_positional_light_count, p_voxel_gi_count, p_fog_volumes);
+ }
+}
+
+/* Lighting */
+
+void RenderForwardClustered::setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents) {
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, p_transform, p_half_extents);
+ }
+}
+
+void RenderForwardClustered::setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) {
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_light(p_type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, p_transform, p_radius, p_spot_aperture);
+ }
+}
+
+void RenderForwardClustered::setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents) {
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, p_transform, p_half_extents);
+ }
+}
+
+/* Render scene */
+
+void RenderForwardClustered::_process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_render_buffers.is_null());
+ ERR_FAIL_COND(p_environment.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ RENDER_TIMESTAMP("Process SSAO");
+
+ RendererRD::SSEffects::SSAOSettings settings;
+ settings.radius = environment_get_ssao_radius(p_environment);
+ settings.intensity = environment_get_ssao_intensity(p_environment);
+ settings.power = environment_get_ssao_power(p_environment);
+ settings.detail = environment_get_ssao_detail(p_environment);
+ settings.horizon = environment_get_ssao_horizon(p_environment);
+ settings.sharpness = environment_get_ssao_sharpness(p_environment);
+
+ settings.quality = ssao_quality;
+ settings.half_size = ssao_half_size;
+ settings.adaptive_target = ssao_adaptive_target;
+ settings.blur_passes = ssao_blur_passes;
+ settings.fadeout_from = ssao_fadeout_from;
+ settings.fadeout_to = ssao_fadeout_to;
+ settings.full_screen_size = p_render_buffers->get_internal_size();
+
+ ss_effects->ssao_allocate_buffers(rb_data->ss_effects_data.ssao, settings, rb_data->ss_effects_data.linear_depth);
+ ss_effects->generate_ssao(rb_data->ss_effects_data.ssao, p_normal_buffer, p_projection, settings);
+}
+
+void RenderForwardClustered::_process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_render_buffers.is_null());
+ ERR_FAIL_COND(p_environment.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ RENDER_TIMESTAMP("Process SSIL");
+
+ RendererRD::SSEffects::SSILSettings settings;
+ settings.radius = environment_get_ssil_radius(p_environment);
+ settings.intensity = environment_get_ssil_intensity(p_environment);
+ settings.sharpness = environment_get_ssil_sharpness(p_environment);
+ settings.normal_rejection = environment_get_ssil_normal_rejection(p_environment);
+
+ settings.quality = ssil_quality;
+ settings.half_size = ssil_half_size;
+ settings.adaptive_target = ssil_adaptive_target;
+ settings.blur_passes = ssil_blur_passes;
+ settings.fadeout_from = ssil_fadeout_from;
+ settings.fadeout_to = ssil_fadeout_to;
+ settings.full_screen_size = p_render_buffers->get_internal_size();
+
+ Projection correction;
+ correction.set_depth_correction(true);
+ Projection projection = correction * p_projection;
+ Transform3D transform = p_transform;
+ transform.set_origin(Vector3(0.0, 0.0, 0.0));
+ Projection last_frame_projection = rb_data->ss_effects_data.last_frame_projection * Projection(rb_data->ss_effects_data.last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse();
+
+ ss_effects->ssil_allocate_buffers(rb_data->ss_effects_data.ssil, settings, rb_data->ss_effects_data.linear_depth);
+ ss_effects->screen_space_indirect_lighting(rb_data->ss_effects_data.ssil, p_normal_buffer, p_projection, last_frame_projection, settings);
+ rb_data->ss_effects_data.last_frame_projection = projection;
+ rb_data->ss_effects_data.last_frame_transform = transform;
+}
+
+void RenderForwardClustered::_copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ if (rb_data->ss_effects_data.ssil.last_frame.is_valid()) {
+ Size2i size = p_render_buffers->get_internal_size();
+ RID texture = p_render_buffers->get_internal_texture();
+ copy_effects->copy_to_rect(texture, rb_data->ss_effects_data.ssil.last_frame, Rect2i(0, 0, size.x, size.y));
+
+ int width = size.x;
+ int height = size.y;
+ for (int i = 0; i < rb_data->ss_effects_data.ssil.last_frame_slices.size() - 1; i++) {
+ width = MAX(1, width >> 1);
+ height = MAX(1, height >> 1);
+ copy_effects->make_mipmap(rb_data->ss_effects_data.ssil.last_frame_slices[i], rb_data->ss_effects_data.ssil.last_frame_slices[i + 1], Size2i(width, height));
+ }
+ }
+}
+
+void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer) {
+ // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ Ref<RenderBufferDataForwardClustered> rb_data;
+ if (rb.is_valid()) {
+ rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ }
+
+ if (rb.is_valid() && p_use_gi && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ sdfgi->store_probes();
+ }
+
+ p_render_data->cube_shadows.clear();
+ p_render_data->shadows.clear();
+ p_render_data->directional_shadows.clear();
+
+ Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
+ float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier();
+ {
+ for (int i = 0; i < p_render_data->render_shadow_count; i++) {
+ RID li = p_render_data->render_shadows[i].light;
+ RID base = light_storage->light_instance_get_base_light(li);
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+ p_render_data->directional_shadows.push_back(i);
+ } else if (light_storage->light_get_type(base) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+ p_render_data->cube_shadows.push_back(i);
+ } else {
+ p_render_data->shadows.push_back(i);
+ }
+ }
+
+ //cube shadows are rendered in their own way
+ for (uint32_t i = 0; i < p_render_data->cube_shadows.size(); i++) {
+ _render_shadow_pass(p_render_data->render_shadows[p_render_data->cube_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->cube_shadows[i]].pass, p_render_data->render_shadows[p_render_data->cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
+ }
+
+ 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();
+ }
+ }
+
+ // Render GI
+
+ bool render_shadows = p_render_data->directional_shadows.size() || p_render_data->shadows.size();
+ bool render_gi = rb.is_valid() && p_use_gi;
+
+ if (render_shadows && render_gi) {
+ RENDER_TIMESTAMP("Render GI + Render Shadows (Parallel)");
+ } else if (render_shadows) {
+ RENDER_TIMESTAMP("Render Shadows");
+ } else if (render_gi) {
+ RENDER_TIMESTAMP("Render GI");
+ }
+
+ //prepare shadow rendering
+ if (render_shadows) {
+ _render_shadow_begin();
+
+ //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 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_process();
+ }
+
+ //start GI
+ if (render_gi) {
+ gi.process_gi(rb, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances);
+ }
+
+ //Do shadow rendering (in parallel with GI)
+ if (render_shadows) {
+ _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER);
+ }
+
+ if (render_gi) {
+ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier
+ }
+
+ if (rb_data.is_valid() && ss_effects) {
+ if (p_use_ssao || p_use_ssil) {
+ Size2i size = rb->get_internal_size();
+
+ bool invalidate_uniform_set = false;
+ if (rb_data->ss_effects_data.linear_depth.is_null()) {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16_SFLOAT;
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ tf.width = (size.x + 1) / 2;
+ tf.height = (size.y + 1) / 2;
+ tf.mipmaps = 5;
+ tf.array_layers = 4;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ rb_data->ss_effects_data.linear_depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(rb_data->ss_effects_data.linear_depth, "SS Effects Depth");
+ for (uint32_t i = 0; i < tf.mipmaps; i++) {
+ RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb_data->ss_effects_data.linear_depth, 0, i, 1, RD::TEXTURE_SLICE_2D_ARRAY);
+ rb_data->ss_effects_data.linear_depth_slices.push_back(slice);
+ RD::get_singleton()->set_resource_name(slice, "SS Effects Depth Mip " + itos(i) + " ");
+ }
+ invalidate_uniform_set = true;
+ }
+
+ RID depth_texture = rb->get_depth_texture();
+ ss_effects->downsample_depth(depth_texture, rb_data->ss_effects_data.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->scene_data->cam_projection);
+ }
+
+ if (p_use_ssao) {
+ // TODO make these proper stereo
+ _process_ssao(rb, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection);
+ }
+
+ if (p_use_ssil) {
+ // TODO make these proper stereo
+ _process_ssil(rb, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform);
+ }
+ }
+
+ //full barrier here, we need raster, transfer and compute and it depends from the previous work
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL);
+
+ if (current_cluster_builder) {
+ current_cluster_builder->begin(p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, !p_render_data->reflection_probe.is_valid());
+ }
+
+ bool using_shadows = true;
+
+ if (p_render_data->reflection_probe.is_valid()) {
+ if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ using_shadows = false;
+ }
+ } else {
+ //do not render reflections when rendering a reflection probe
+ light_storage->update_reflection_probe_buffer(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment);
+ }
+
+ uint32_t directional_light_count = 0;
+ uint32_t positional_light_count = 0;
+ light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
+ texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse());
+
+ p_render_data->directional_light_count = directional_light_count;
+
+ if (current_cluster_builder) {
+ current_cluster_builder->bake_cluster();
+ }
+
+ if (rb.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);
+ }
+}
+
+void RenderForwardClustered::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ Size2i internal_size = p_render_buffers->get_internal_size();
+ bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
+ uint32_t view_count = p_render_buffers->get_view_count();
+
+ if (!can_use_effects) {
+ //just copy
+ copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), RID(), view_count);
+ return;
+ }
+
+ ERR_FAIL_COND(p_environment.is_null());
+ ERR_FAIL_COND(!environment_get_ssr_enabled(p_environment));
+
+ Size2i half_size = Size2i(internal_size.x / 2, internal_size.y / 2);
+ if (rb_data->ss_effects_data.ssr.output.is_null()) {
+ ss_effects->ssr_allocate_buffers(rb_data->ss_effects_data.ssr, _render_buffers_get_color_format(), ssr_roughness_quality, half_size, view_count);
+ }
+ RID texture_slices[RendererSceneRender::MAX_RENDER_VIEWS];
+ RID depth_slices[RendererSceneRender::MAX_RENDER_VIEWS];
+ for (uint32_t v = 0; v < view_count; v++) {
+ texture_slices[v] = p_render_buffers->get_internal_texture(v);
+ depth_slices[v] = p_render_buffers->get_depth_texture(v);
+ }
+ ss_effects->screen_space_reflection(rb_data->ss_effects_data.ssr, texture_slices, p_normal_slices, ssr_roughness_quality, p_metallic_slices, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), view_count, p_projections, p_eye_offsets);
+ copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), rb_data->ss_effects_data.ssr.output, view_count);
+}
+
+void RenderForwardClustered::_process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Size2i internal_size = p_render_buffers->get_internal_size();
+ bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
+
+ if (!can_use_effects) {
+ //just copy
+ return;
+ }
+
+ p_render_buffers->allocate_blur_textures();
+
+ for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) {
+ RID internal_texture = p_render_buffers->get_internal_texture(v);
+ RID depth_texture = p_render_buffers->get_depth_texture(v);
+ ss_effects->sub_surface_scattering(p_render_buffers, internal_texture, depth_texture, p_camera, internal_size, sss_scale, sss_depth_scale, sss_quality);
+ }
+}
+
void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
Ref<RenderSceneBuffersRD> rb;
Ref<RenderBufferDataForwardClustered> rb_data;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
@@ -1070,6 +1561,54 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
//first of all, make a new render pass
//fill up ubo
+ RENDER_TIMESTAMP("Prepare 3D Scene");
+
+ // sdfgi first
+ _update_sdfgi(p_render_data);
+
+ // assign render indices to voxel_gi_instances
+ for (uint32_t i = 0; i < (uint32_t)p_render_data->voxel_gi_instances->size(); i++) {
+ RID voxel_gi_instance = (*p_render_data->voxel_gi_instances)[i];
+ gi.voxel_gi_instance_set_render_index(voxel_gi_instance, i);
+ }
+
+ // obtain cluster builder
+ if (rb_data.is_valid()) {
+ current_cluster_builder = rb_data->cluster_builder;
+ } else if (light_storage->owns_reflection_probe_instance(p_render_data->reflection_probe)) {
+ current_cluster_builder = light_storage->reflection_probe_instance_get_cluster_builder(p_render_data->reflection_probe, &cluster_builder_shared);
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ light_storage->reflection_probe_set_baked_exposure(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe), RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes));
+ }
+ } else {
+ ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
+ current_cluster_builder = nullptr;
+ }
+
+ p_render_data->voxel_gi_count = 0;
+
+ if (rb.is_valid()) {
+ if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ if (sdfgi.is_valid()) {
+ sdfgi->update_cascades();
+ sdfgi->pre_process_gi(p_render_data->scene_data->cam_transform, p_render_data);
+ sdfgi->update_light();
+ }
+ }
+
+ gi.setup_voxel_gi_instances(p_render_data, p_render_data->render_buffers, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances, p_render_data->voxel_gi_count);
+ }
+
+ if (current_cluster_builder != nullptr) {
+ p_render_data->cluster_buffer = current_cluster_builder->get_cluster_buffer();
+ p_render_data->cluster_size = current_cluster_builder->get_cluster_size();
+ p_render_data->cluster_max_elements = current_cluster_builder->get_max_cluster_elements();
+ }
+
+ _update_vrs(rb);
+
RENDER_TIMESTAMP("Setup 3D Scene");
// check if we need motion vectors
@@ -1153,15 +1692,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags);
color_only_framebuffer = rb_data->get_color_only_fb();
} else if (p_render_data->reflection_probe.is_valid()) {
- uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+ uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
screen_size.x = resolution;
screen_size.y = resolution;
- color_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+ color_framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
color_only_framebuffer = color_framebuffer;
- depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+ depth_framebuffer = light_storage->reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
- if (RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
p_render_data->environment = RID(); //no environment on interiors
}
@@ -1538,6 +2077,229 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_render_buffers_post_process_and_tonemap(p_render_data);
}
+
+ if (rb.is_valid()) {
+ _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex);
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ Vector<RID> view_rids;
+
+ // SDFGI renders at internal resolution, need to check if our debug correctly supports outputting upscaled.
+ Size2i size = rb->get_internal_size();
+ RID source_texture = rb->get_internal_texture();
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ view_rids.push_back(rb->get_internal_texture(v));
+ }
+
+ sdfgi->debug_draw(p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids);
+ }
+ }
+}
+
+void RenderForwardClustered::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->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);
+
+ RID render_target = p_render_buffers->get_render_target();
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb_data->ss_effects_data.ssao.ao_final.is_valid()) {
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(rb_data->ss_effects_data.ssao.ao_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 && rb_data->ss_effects_data.ssil.ssil_final.is_valid()) {
+ Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(rb_data->ss_effects_data.ssil.ssil_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)) {
+ Size2 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);
+ }
+}
+
+void RenderForwardClustered::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &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) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
+ ERR_FAIL_COND(!light_storage->owns_light_instance(p_light));
+
+ RID base = light_storage->light_instance_get_base_light(p_light);
+
+ Rect2i atlas_rect;
+ uint32_t atlas_size = 1;
+ RID atlas_fb;
+
+ bool using_dual_paraboloid = false;
+ bool using_dual_paraboloid_flip = false;
+ Vector2i dual_paraboloid_offset;
+ RID render_fb;
+ RID render_texture;
+ float zfar;
+
+ bool use_pancake = false;
+ bool render_cubemap = false;
+ bool finalize_cubemap = false;
+
+ bool flip_y = false;
+
+ Projection light_projection;
+ Transform3D light_transform;
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+ //set pssm stuff
+ uint64_t last_scene_shadow_pass = light_storage->light_instance_get_shadow_pass(p_light);
+ if (last_scene_shadow_pass != get_scene_pass()) {
+ light_storage->light_instance_set_directional_rect(p_light, light_storage->get_directional_shadow_rect());
+ light_storage->directional_shadow_increase_current_light();
+ light_storage->light_instance_set_shadow_pass(p_light, get_scene_pass());
+ }
+
+ 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);
+
+ atlas_rect = light_storage->light_instance_get_directional_rect(p_light);
+
+ if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+ atlas_rect.size.width /= 2;
+ atlas_rect.size.height /= 2;
+
+ if (p_pass == 1) {
+ atlas_rect.position.x += atlas_rect.size.width;
+ } else if (p_pass == 2) {
+ atlas_rect.position.y += atlas_rect.size.height;
+ } else if (p_pass == 3) {
+ atlas_rect.position += atlas_rect.size;
+ }
+ } else if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+ atlas_rect.size.height /= 2;
+
+ if (p_pass == 0) {
+ } else {
+ atlas_rect.position.y += atlas_rect.size.height;
+ }
+ }
+
+ int directional_shadow_size = light_storage->directional_shadow_get_size();
+ atlas_rect.position /= directional_shadow_size;
+ atlas_rect.size /= directional_shadow_size;
+
+ light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect);
+
+ zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
+
+ render_fb = light_storage->direction_shadow_get_fb();
+ render_texture = RID();
+ flip_y = true;
+
+ } else {
+ //set from shadow atlas
+
+ ERR_FAIL_COND(!light_storage->owns_shadow_atlas(p_shadow_atlas));
+ ERR_FAIL_COND(!light_storage->shadow_atlas_owns_light_instance(p_shadow_atlas, p_light));
+
+ RSG::light_storage->shadow_atlas_update(p_shadow_atlas);
+
+ uint32_t key = light_storage->shadow_atlas_get_light_instance_key(p_shadow_atlas, p_light);
+
+ uint32_t quadrant = (key >> RendererRD::LightStorage::QUADRANT_SHIFT) & 0x3;
+ uint32_t shadow = key & RendererRD::LightStorage::SHADOW_INDEX_MASK;
+ uint32_t subdivision = light_storage->shadow_atlas_get_quadrant_subdivision(p_shadow_atlas, quadrant);
+
+ ERR_FAIL_INDEX((int)shadow, light_storage->shadow_atlas_get_quadrant_shadow_size(p_shadow_atlas, quadrant));
+
+ uint32_t shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas);
+ uint32_t quadrant_size = shadow_atlas_size >> 1;
+
+ atlas_rect.position.x = (quadrant & 1) * quadrant_size;
+ atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / subdivision);
+ atlas_rect.position.x += (shadow % subdivision) * shadow_size;
+ atlas_rect.position.y += (shadow / subdivision) * shadow_size;
+
+ atlas_rect.size.width = shadow_size;
+ atlas_rect.size.height = shadow_size;
+
+ zfar = light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_OMNI) {
+ bool wrap = (shadow + 1) % subdivision == 0;
+ dual_paraboloid_offset = wrap ? Vector2i(1 - subdivision, 1) : Vector2i(1, 0);
+
+ if (light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+ render_texture = light_storage->get_cubemap(shadow_size / 2);
+ render_fb = light_storage->get_cubemap_fb(shadow_size / 2, p_pass);
+
+ 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);
+ render_cubemap = true;
+ finalize_cubemap = p_pass == 5;
+ atlas_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+
+ atlas_size = shadow_atlas_size;
+
+ if (p_pass == 0) {
+ _render_shadow_begin();
+ }
+
+ } else {
+ atlas_rect.position.x += 1;
+ atlas_rect.position.y += 1;
+ atlas_rect.size.x -= 2;
+ atlas_rect.size.y -= 2;
+
+ atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset;
+
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
+
+ using_dual_paraboloid = true;
+ using_dual_paraboloid_flip = p_pass == 1;
+ render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+ flip_y = true;
+ }
+
+ } else if (light_storage->light_get_type(base) == RS::LIGHT_SPOT) {
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
+
+ render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+
+ flip_y = true;
+ }
+ }
+
+ if (render_cubemap) {
+ //rendering to cubemap
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info);
+ if (finalize_cubemap) {
+ _render_shadow_process();
+ _render_shadow_end();
+ //reblit
+ Rect2 atlas_rect_norm = atlas_rect;
+ atlas_rect_norm.position /= float(atlas_size);
+ atlas_rect_norm.size /= float(atlas_size);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
+ atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
+
+ //restore transform so it can be properly used
+ light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0);
+ }
+
+ } 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);
+ }
}
void RenderForwardClustered::_render_shadow_begin() {
@@ -1894,7 +2656,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_base_uniforms_changed() {
+void RenderForwardClustered::base_uniforms_changed() {
if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
}
@@ -2010,14 +2772,14 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_omni_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_spot_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer());
uniforms.push_back(u);
}
@@ -2025,14 +2787,14 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_reflection_probe_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.append_id(get_directional_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer());
uniforms.push_back(u);
}
{
@@ -2069,7 +2831,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_decal_buffer());
+ u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer());
uniforms.push_back(u);
}
@@ -2147,7 +2909,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
uniforms.push_back(u);
}
{
- RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
+ RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? light_storage->reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
RD::Uniform u;
u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
@@ -2164,7 +2926,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 = shadow_atlas_get_texture(p_render_data->shadow_atlas);
+ texture = RendererRD::LightStorage::get_singleton()->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);
@@ -2176,8 +2938,8 @@ 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 && directional_shadow_get_texture().is_valid()) {
- u.append_id(directional_shadow_get_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());
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH));
}
@@ -2191,7 +2953,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
if (p_render_data && i < p_render_data->lightmaps->size()) {
- RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
+ RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
RID texture = light_storage->lightmap_get_texture(base);
RID rd_texture = texture_storage->texture_get_rd_texture(texture);
u.append_id(rd_texture);
@@ -2267,7 +3029,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID aot = rb_data.is_valid() ? rb->get_ao_texture() : RID();
+ RID aot = rb_data.is_valid() ? rb_data->get_ao_texture() : RID();
RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
@@ -2353,7 +3115,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 20;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID();
+ RID ssil = rb_data.is_valid() ? rb_data->get_ssil_texture() : RID();
RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
@@ -2831,7 +3593,7 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
ginstance->store_transform_cache = store_transform;
ginstance->can_sdfgi = false;
- if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) {
+ if (!RendererRD::LightStorage::get_singleton()->lightmap_instance_is_valid(ginstance->lightmap_instance)) {
if (ginstance->voxel_gi_instances[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) {
ginstance->can_sdfgi = true;
}
@@ -3013,7 +3775,7 @@ void RenderForwardClustered::_update_shader_quality_settings() {
scene_shader.set_default_specialization_constants(spec_constants);
- _base_uniforms_changed(); //also need this
+ base_uniforms_changed(); //also need this
}
RenderForwardClustered::RenderForwardClustered() {
@@ -3056,15 +3818,31 @@ RenderForwardClustered::RenderForwardClustered() {
scene_shader.init(defines);
}
+ /* shadow sampler */
+ {
+ RD::SamplerState sampler;
+ sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler.enable_compare = true;
+ sampler.compare_op = RD::COMPARE_OP_LESS;
+ shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ }
+
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
_update_shader_quality_settings();
resolve_effects = memnew(RendererRD::Resolve());
taa = memnew(RendererRD::TAA);
+ ss_effects = memnew(RendererRD::SSEffects);
}
RenderForwardClustered::~RenderForwardClustered() {
+ if (ss_effects != nullptr) {
+ memdelete(ss_effects);
+ ss_effects = nullptr;
+ }
+
if (taa != nullptr) {
memdelete(taa);
taa = nullptr;
@@ -3075,7 +3853,8 @@ RenderForwardClustered::~RenderForwardClustered() {
resolve_effects = nullptr;
}
- directional_shadow_atlas_set_size(0);
+ RD::get_singleton()->free(shadow_sampler);
+ RSG::light_storage->directional_shadow_atlas_set_size(0);
{
for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) {
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 1e70f6880c..382d66a5a7 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -32,7 +32,9 @@
#define RENDER_FORWARD_CLUSTERED_H
#include "core/templates/paged_allocator.h"
+#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/effects/resolve.h"
+#include "servers/rendering/renderer_rd/effects/ss_effects.h"
#include "servers/rendering/renderer_rd/effects/taa.h"
#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
@@ -99,7 +101,21 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
public:
- //for rendering, may be MSAAd
+ ClusterBuilderRD *cluster_builder = nullptr;
+
+ struct SSEffectsData {
+ RID linear_depth;
+ Vector<RID> linear_depth_slices;
+
+ RID downsample_uniform_set;
+
+ Projection last_frame_projection;
+ Transform3D last_frame_transform;
+
+ RendererRD::SSEffects::SSAORenderBuffers ssao;
+ RendererRD::SSEffects::SSILRenderBuffers ssil;
+ RendererRD::SSEffects::SSRRenderBuffers ssr;
+ } ss_effects_data;
enum DepthFrameBufferType {
DEPTH_FB,
@@ -139,6 +155,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID get_depth_fb(DepthFrameBufferType p_type = DEPTH_FB);
RID get_specular_only_fb();
+ RID get_ao_texture() const { return ss_effects_data.ssao.ao_final; }
+ RID get_ssil_texture() const { return ss_effects_data.ssil.ssil_final; }
+
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
virtual void free_data() override;
};
@@ -149,10 +168,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- virtual void _base_uniforms_changed() override;
- virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
- virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
-
bool base_uniform_set_updated = false;
void _update_render_base_uniform_set();
RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture);
@@ -558,16 +573,54 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void _update_shader_quality_settings() override;
+ /* Effects */
+
RendererRD::Resolve *resolve_effects = nullptr;
RendererRD::TAA *taa = nullptr;
+ RendererRD::SSEffects *ss_effects = nullptr;
+
+ /* Cluster builder */
+
+ ClusterBuilderSharedDataRD cluster_builder_shared;
+ ClusterBuilderRD *current_cluster_builder = nullptr;
+
+ /* SDFGI */
+ void _update_sdfgi(RenderDataRD *p_render_data);
+
+ /* Volumetric fog */
+ RID shadow_sampler;
+
+ void _update_volumetric_fog(Ref<RenderSceneBuffersRD> 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<RID> &p_fog_volumes);
+
+ /* Render shadows */
+
+ void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &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_begin();
+ void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &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();
+ void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+
+ /* Render Scene */
+ void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection);
+ void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform);
+ void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers);
+ void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
+ void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
+ void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
+
+ /* Debug */
+ void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers);
protected:
- virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+ /* setup */
- virtual void _render_shadow_begin() override;
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &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) override;
- virtual void _render_shadow_process() override;
- virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
+ virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+ virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+
+ /* Rendering */
+
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+ virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) override;
virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
@@ -577,6 +630,15 @@ protected:
public:
static RenderForwardClustered *get_singleton() { return singleton; }
+ ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; }
+ RendererRD::SSEffects *get_ss_effects() { return ss_effects; }
+
+ /* callback from updating our lighting UBOs, used to populate cluster builder */
+ virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents) override;
+ virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) override;
+ virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents) override;
+
+ virtual void base_uniforms_changed() override;
_FORCE_INLINE_ virtual void update_uniform_sets() override {
base_uniform_set_updated = true;
_update_render_base_uniform_set();