From d9eb9665daac64e5eeb78ea1e3ebd39c08f2ad15 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Mon, 15 May 2023 14:08:56 +1000 Subject: [PATCH] Draw frustum splices ontop of direction shadow atlas for debug purposes --- doc/classes/RenderingServer.xml | 2 + .../renderer_rd/effects/debug_effects.cpp | 328 ++++++++++++++++++ .../renderer_rd/effects/debug_effects.h | 85 +++++ .../render_forward_clustered.cpp | 30 +- .../render_forward_clustered.h | 2 +- .../forward_mobile/render_forward_mobile.cpp | 2 +- .../renderer_rd/renderer_scene_render_rd.cpp | 51 ++- .../renderer_rd/renderer_scene_render_rd.h | 4 +- .../shaders/effects/shadow_frustum.glsl | 41 +++ 9 files changed, 515 insertions(+), 30 deletions(-) create mode 100644 servers/rendering/renderer_rd/effects/debug_effects.cpp create mode 100644 servers/rendering/renderer_rd/effects/debug_effects.h create mode 100644 servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 840a594ec4e..8a8c1ef1f16 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -4625,6 +4625,8 @@ Draws the shadow atlas that stores shadows from [DirectionalLight3D]s in the upper left quadrant of the [Viewport]. + The slice of the camera frustum related to the shadow map cascade is superimposed to visualize coverage. The color of each slice matches the colors used for [constant VIEWPORT_DEBUG_DRAW_PSSM_SPLITS]. When shadow cascades are blended the overlap is taken into account when drawing the frustum slices. + The last cascade shows all frustum slices to illustrate the coverage of all slices. Draws the estimated scene luminance. This is a 1×1 texture that is generated when autoexposure is enabled to control the scene's exposure. diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp new file mode 100644 index 00000000000..8cd3c224831 --- /dev/null +++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp @@ -0,0 +1,328 @@ +/**************************************************************************/ +/* debug_effects.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "debug_effects.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" +#include "servers/rendering/renderer_rd/storage_rd/light_storage.h" +#include "servers/rendering/renderer_rd/storage_rd/material_storage.h" +#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h" + +using namespace RendererRD; + +DebugEffects::DebugEffects() { + { + // Shadow Frustum debug shader + Vector modes; + modes.push_back(""); + + shadow_frustum.shader.initialize(modes); + shadow_frustum.shader_version = shadow_frustum.shader.version_create(); + + RD::PipelineRasterizationState raster_state = RD::PipelineRasterizationState(); + shadow_frustum.pipelines[SFP_TRANSPARENT].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0); + + raster_state.wireframe = true; + shadow_frustum.pipelines[SFP_WIREFRAME].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_LINES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } +} + +void DebugEffects::_create_frustum_arrays() { + if (frustum.vertex_buffer.is_null()) { + // Create vertex buffer, but don't put data in it yet + frustum.vertex_buffer = RD::get_singleton()->vertex_buffer_create(8 * sizeof(float) * 3, Vector(), false); + + Vector attributes; + Vector buffers; + RD::VertexAttribute vd; + + vd.location = 0; + vd.stride = sizeof(float) * 3; + vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + + attributes.push_back(vd); + buffers.push_back(frustum.vertex_buffer); + + frustum.vertex_format = RD::get_singleton()->vertex_format_create(attributes); + frustum.vertex_array = RD::get_singleton()->vertex_array_create(8, frustum.vertex_format, buffers); + } + + if (frustum.index_buffer.is_null()) { + uint32_t indices[6 * 2 * 3] = { + // Far + 0, 1, 2, // FLT, FLB, FRT + 1, 3, 2, // FLB, FRB, FRT + // Near + 4, 6, 5, // NLT, NRT, NLB + 6, 7, 5, // NRT, NRB, NLB + // Left + 0, 4, 1, // FLT, NLT, FLB + 4, 5, 1, // NLT, NLB, FLB + // Right + 6, 2, 7, // NRT, FRT, NRB + 2, 3, 7, // FRT, FRB, NRB + // Top + 0, 2, 4, // FLT, FRT, NLT + 2, 6, 4, // FRT, NRT, NLT + // Bottom + 5, 7, 1, // NLB, NRB, FLB, + 7, 3, 1, // NRB, FRB, FLB + }; + + // Create our index_array + PackedByteArray data; + data.resize(6 * 2 * 3 * 4); + { + uint8_t *w = data.ptrw(); + int *p32 = (int *)w; + for (int i = 0; i < 6 * 2 * 3; i++) { + *p32 = indices[i]; + p32++; + } + } + + frustum.index_buffer = RD::get_singleton()->index_buffer_create(6 * 2 * 3, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, data); + frustum.index_array = RD::get_singleton()->index_array_create(frustum.index_buffer, 0, 6 * 2 * 3); + } + + if (frustum.lines_buffer.is_null()) { + uint32_t indices[12 * 2] = { + 0, 1, // FLT - FLB + 1, 3, // FLB - FRB + 3, 2, // FRB - FRT + 2, 0, // FRT - FLT + + 4, 6, // NLT - NRT + 6, 7, // NRT - NRB + 7, 5, // NRB - NLB + 5, 4, // NLB - NLT + + 0, 4, // FLT - NLT + 1, 5, // FLB - NLB + 2, 6, // FRT - NRT + 3, 7, // FRB - NRB + }; + + // Create our lines_array + PackedByteArray data; + data.resize(12 * 2 * 4); + { + uint8_t *w = data.ptrw(); + int *p32 = (int *)w; + for (int i = 0; i < 12 * 2; i++) { + *p32 = indices[i]; + p32++; + } + } + + frustum.lines_buffer = RD::get_singleton()->index_buffer_create(12 * 2, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, data); + frustum.lines_array = RD::get_singleton()->index_array_create(frustum.lines_buffer, 0, 12 * 2); + } +} + +DebugEffects::~DebugEffects() { + shadow_frustum.shader.version_free(shadow_frustum.shader_version); + + // Destroy vertex buffer and array. + if (frustum.vertex_buffer.is_valid()) { + RD::get_singleton()->free(frustum.vertex_buffer); // Array gets freed as dependency. + } + + // Destroy index buffer and array, + if (frustum.index_buffer.is_valid()) { + RD::get_singleton()->free(frustum.index_buffer); // Array gets freed as dependency. + } + + // Destroy lines buffer and array. + if (frustum.lines_buffer.is_valid()) { + RD::get_singleton()->free(frustum.lines_buffer); // Array gets freed as dependency. + } +} + +void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + + RID base = light_storage->light_instance_get_base_light(p_light); + ERR_FAIL_COND(light_storage->light_get_type(base) != RS::LIGHT_DIRECTIONAL); + + // Make sure our buffers and arrays exist. + _create_frustum_arrays(); + + // Setup a points buffer for our view frustum. + PackedByteArray points; + points.resize(8 * sizeof(float) * 3); + + // Get info about our splits. + RS::LightDirectionalShadowMode shadow_mode = light_storage->light_directional_get_shadow_mode(base); + bool overlap = light_storage->light_directional_get_blend_splits(base); + int splits = 1; + if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + splits = 4; + } else if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + splits = 2; + } + + // Setup our camera info (this is mostly a duplicate of the logic found in RendererSceneCull::_light_instance_setup_directional_shadow). + bool is_orthogonal = p_cam_projection.is_orthogonal(); + real_t aspect = p_cam_projection.get_aspect(); + real_t fov = 0.0; + Vector2 vp_he; + if (is_orthogonal) { + vp_he = p_cam_projection.get_viewport_half_extents(); + } else { + fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it + } + real_t min_distance = p_cam_projection.get_z_near(); + real_t max_distance = p_cam_projection.get_z_far(); + real_t shadow_max = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); + if (shadow_max > 0 && !is_orthogonal) { + max_distance = MIN(shadow_max, max_distance); + } + + // Make sure we've not got bad info coming in. + max_distance = MAX(max_distance, min_distance + 0.001); + min_distance = MIN(min_distance, max_distance); + real_t range = max_distance - min_distance; + + real_t distances[5]; + distances[0] = min_distance; + for (int i = 0; i < splits; i++) { + distances[i + 1] = min_distance + RSG::light_storage->light_get_param(base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range; + }; + distances[splits] = max_distance; + + Color colors[4] = { + Color(1.0, 0.0, 0.0, 0.1), + Color(0.0, 1.0, 0.0, 0.1), + Color(0.0, 0.0, 1.0, 0.1), + Color(1.0, 1.0, 0.0, 0.1), + }; + + for (int split = 0; split < splits; split++) { + // Load frustum points into vertex buffer. + uint8_t *w = points.ptrw(); + Vector3 *vw = (Vector3 *)w; + + Projection projection; + + if (is_orthogonal) { + projection.set_orthogonal(vp_he.y * 2.0, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], false); + } else { + projection.set_perspective(fov, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], true); + } + + bool res = projection.get_endpoints(p_cam_transform, vw); + ERR_CONTINUE(!res); + + RD::get_singleton()->buffer_update(frustum.vertex_buffer, 0, 8 * sizeof(float) * 3, w); + + // Get our light projection info. + Projection light_projection = light_storage->light_instance_get_shadow_camera(p_light, split); + Transform3D light_transform = light_storage->light_instance_get_shadow_transform(p_light, split); + Rect2 atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, split); + + if (!is_orthogonal) { + light_transform.orthogonalize(); + } + + // Setup our push constant. + ShadowFrustumPushConstant push_constant; + MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp); + push_constant.color[0] = colors[split].r; + push_constant.color[1] = colors[split].g; + push_constant.color[2] = colors[split].b; + push_constant.color[3] = colors[split].a; + + // Adjust our rect to our atlas position. + Rect2 rect = p_rect; + rect.position.x += atlas_rect_norm.position.x * rect.size.x; + rect.position.y += atlas_rect_norm.position.y * rect.size.y; + rect.size.x *= atlas_rect_norm.size.x; + rect.size.y *= atlas_rect_norm.size.y; + + // And draw our frustum. + RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector(), 1.0, 0, rect); + + RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + + pipeline = shadow_frustum.pipelines[SFP_WIREFRAME].get_render_pipeline(frustum.vertex_format, fb_format_id); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.lines_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + + RD::get_singleton()->draw_list_end(); + + if (split < (splits - 1) && splits > 1) { + // Also draw it in the last split so we get a proper overview of the whole view frustum... + + // Get our light projection info. + light_projection = light_storage->light_instance_get_shadow_camera(p_light, (splits - 1)); + light_transform = light_storage->light_instance_get_shadow_transform(p_light, (splits - 1)); + atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, (splits - 1)); + + if (!is_orthogonal) { + light_transform.orthogonalize(); + } + + // Update our push constant. + MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp); + push_constant.color[0] = colors[split].r; + push_constant.color[1] = colors[split].g; + push_constant.color[2] = colors[split].b; + push_constant.color[3] = colors[split].a; + + // Adjust our rect to our atlas position. + rect = p_rect; + rect.position.x += atlas_rect_norm.position.x * rect.size.x; + rect.position.y += atlas_rect_norm.position.y * rect.size.y; + rect.size.x *= atlas_rect_norm.size.x; + rect.size.y *= atlas_rect_norm.size.y; + + draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector(), 1.0, 0, rect); + + pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + + RD::get_singleton()->draw_list_end(); + } + } +} diff --git a/servers/rendering/renderer_rd/effects/debug_effects.h b/servers/rendering/renderer_rd/effects/debug_effects.h new file mode 100644 index 00000000000..21b7b03f849 --- /dev/null +++ b/servers/rendering/renderer_rd/effects/debug_effects.h @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* debug_effects.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DEBUG_EFFECTS_RD_H +#define DEBUG_EFFECTS_RD_H + +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" + +#include "servers/rendering_server.h" + +namespace RendererRD { + +class DebugEffects { +private: + struct { + RD::VertexFormatID vertex_format; + RID vertex_buffer; + RID vertex_array; + + RID index_buffer; + RID index_array; + + RID lines_buffer; + RID lines_array; + } frustum; + + struct ShadowFrustumPushConstant { + float mvp[16]; + float color[4]; + }; + + enum ShadowFrustumPipelines { + SFP_TRANSPARENT, + SFP_WIREFRAME, + SFP_MAX + }; + + struct { + ShadowFrustumShaderRD shader; + RID shader_version; + PipelineCacheRD pipelines[SFP_MAX]; + } shadow_frustum; + + void _create_frustum_arrays(); + +protected: +public: + DebugEffects(); + ~DebugEffects(); + + void draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect); +}; + +} // namespace RendererRD + +#endif // DEBUG_EFFECTS_RD_H 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 eea891792a0..3ae0553a465 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -2091,7 +2091,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); @@ -2109,34 +2109,36 @@ 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(const 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); } } 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 7ab9e67bac4..1466c796621 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -618,7 +618,7 @@ protected: /* 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(const 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 0b4157c5d63..130c5252c58 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -1083,7 +1083,7 @@ 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 */ diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 16bc36f4b83..646bdc54368 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -659,16 +659,18 @@ 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(const RenderDataRD *p_render_data) { + RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); 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); @@ -683,8 +685,27 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref if (RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture().is_valid()) { RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture(); Size2i rtsize = texture_storage->render_target_get_size(render_target); + RID dest_fb = texture_storage->render_target_get_rd_framebuffer(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); + // Determine our display size, try and keep square by using the smallest edge. + Size2i size = 2 * rtsize / 3; + if (size.x < size.y) { + size.y = size.x; + } else if (size.y < size.x) { + size.x = size.y; + } + + copy_effects->copy_to_fb_rect(shadow_atlas_texture, dest_fb, Rect2i(Vector2(), size), false, true); + + // Visualise our view frustum to show coverage. + for (int i = 0; i < p_render_data->render_shadow_count; i++) { + RID light = p_render_data->render_shadows[i].light; + RID base = light_storage->light_instance_get_base_light(light); + + if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) { + debug_effects->draw_shadow_frustum(light, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, dest_fb, Rect2(Size2(), size)); + } + } } } @@ -699,7 +720,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 +728,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); } } @@ -1293,6 +1314,7 @@ void RendererSceneRenderRD::init() { bool can_use_vrs = is_vrs_supported(); bokeh_dof = memnew(RendererRD::BokehDOF(!can_use_storage)); copy_effects = memnew(RendererRD::CopyEffects(!can_use_storage)); + debug_effects = memnew(RendererRD::DebugEffects); luminance = memnew(RendererRD::Luminance(!can_use_storage)); tone_mapper = memnew(RendererRD::ToneMapper); if (can_use_vrs) { @@ -1314,6 +1336,9 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { if (copy_effects) { memdelete(copy_effects); } + if (debug_effects) { + memdelete(debug_effects); + } if (luminance) { memdelete(luminance); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 7c43021eb05..4bce6a172ec 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -37,6 +37,7 @@ #include "servers/rendering/renderer_rd/cluster_builder_rd.h" #include "servers/rendering/renderer_rd/effects/bokeh_dof.h" #include "servers/rendering/renderer_rd/effects/copy_effects.h" +#include "servers/rendering/renderer_rd/effects/debug_effects.h" #include "servers/rendering/renderer_rd/effects/fsr.h" #include "servers/rendering/renderer_rd/effects/luminance.h" #include "servers/rendering/renderer_rd/effects/tone_mapper.h" @@ -106,6 +107,7 @@ protected: RendererRD::ForwardIDStorage *forward_id_storage = nullptr; RendererRD::BokehDOF *bokeh_dof = nullptr; RendererRD::CopyEffects *copy_effects = nullptr; + RendererRD::DebugEffects *debug_effects = nullptr; RendererRD::Luminance *luminance = nullptr; RendererRD::ToneMapper *tone_mapper = nullptr; RendererRD::FSR *fsr = nullptr; @@ -128,7 +130,7 @@ protected: 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(const 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; diff --git a/servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl b/servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl new file mode 100644 index 00000000000..11ec7ec59e1 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/effects/shadow_frustum.glsl @@ -0,0 +1,41 @@ +/* clang-format off */ +#[vertex] + +#version 450 + +#VERSION_DEFINES + +/* clang-format on */ + +layout(push_constant, std430) uniform Info { + mat4 mvp; + vec4 color; +} +info; + +layout(location = 0) in vec3 vertex_attrib; + +void main() { + vec4 vertex = info.mvp * vec4(vertex_attrib, 1.0); + vertex.xyz /= vertex.w; + gl_Position = vec4(vertex.xy, 0.0, 1.0); +} + +/* clang-format off */ +#[fragment] + +#version 450 + +#VERSION_DEFINES + +layout(push_constant, std430) uniform Info { + mat4 mvp; + vec4 color; +} +info; + +layout(location = 0) out vec4 frag_color; + +void main() { + frag_color = info.color; +}