From 31ad99072fb30edc8f4824665ecde57a303aec8a Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sat, 23 Oct 2021 22:04:59 +0200 Subject: [PATCH] Allow changing directional shadow size at run-time Factoring out the directional shadow creation code allows calling it at any time. This works in both GLES3 and GLES2. --- doc/classes/ProjectSettings.xml | 2 +- drivers/gles2/rasterizer_scene_gles2.cpp | 117 +++++++++++++---------- drivers/gles2/rasterizer_scene_gles2.h | 4 + drivers/gles3/rasterizer_scene_gles3.cpp | 58 +++++++---- drivers/gles3/rasterizer_scene_gles3.h | 3 + servers/visual_server.cpp | 2 +- 6 files changed, 114 insertions(+), 72 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 65c6f6d6d97..72652770844 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1297,7 +1297,7 @@ If [code]true[/code], performs a previous depth pass before rendering materials. This increases performance in scenes with high overdraw, when complex materials and lighting are used. - The directional shadow's size in pixels. Higher values will result in sharper shadows, at the cost of performance. The value will be rounded up to the nearest power of 2. + The directional shadow's size in pixels. Higher values will result in sharper shadows, at the cost of performance. The value will be rounded up to the nearest power of 2. This setting can be changed at run-time; the change will be applied immediately. Lower-end override for [member rendering/quality/directional_shadow/size] on mobile devices, due to performance concerns or driver support. diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 31362045e2b..4bd9a37b349 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -64,6 +64,64 @@ static const GLenum _cube_side_enum[6] = { }; +void RasterizerSceneGLES2::directional_shadow_create() { + if (directional_shadow.fbo) { + // Erase existing directional shadow texture to recreate it. + glDeleteTextures(1, &directional_shadow.depth); + glDeleteFramebuffers(1, &directional_shadow.fbo); + + directional_shadow.depth = 0; + directional_shadow.fbo = 0; + } + + directional_shadow.light_count = 0; + directional_shadow.size = next_power_of_2(directional_shadow_size); + + if (directional_shadow.size > storage->config.max_viewport_dimensions[0] || directional_shadow.size > storage->config.max_viewport_dimensions[1]) { + WARN_PRINT("Cannot set directional shadow size larger than maximum hardware supported size of (" + itos(storage->config.max_viewport_dimensions[0]) + ", " + itos(storage->config.max_viewport_dimensions[1]) + "). Setting size to maximum."); + directional_shadow.size = MIN(directional_shadow.size, storage->config.max_viewport_dimensions[0]); + directional_shadow.size = MIN(directional_shadow.size, storage->config.max_viewport_dimensions[1]); + } + + glGenFramebuffers(1, &directional_shadow.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); + + if (storage->config.use_rgba_3d_shadows) { + //maximum compatibility, renderbuffer and RGBA shadow + glGenRenderbuffers(1, &directional_shadow.depth); + glBindRenderbuffer(GL_RENDERBUFFER, directional_shadow.depth); + glRenderbufferStorage(GL_RENDERBUFFER, storage->config.depth_buffer_internalformat, directional_shadow.size, directional_shadow.size); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, directional_shadow.depth); + + glGenTextures(1, &directional_shadow.color); + glBindTexture(GL_TEXTURE_2D, directional_shadow.color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, directional_shadow.size, directional_shadow.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, directional_shadow.color, 0); + } else { + //just a depth buffer + glGenTextures(1, &directional_shadow.depth); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + + glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, nullptr); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + ERR_PRINT("Directional shadow framebuffer status invalid"); + } +} + /* SHADOW ATLAS API */ RID RasterizerSceneGLES2::shadow_atlas_create() { @@ -3986,56 +4044,7 @@ void RasterizerSceneGLES2::initialize() { } } - { - // directional shadows - - directional_shadow.light_count = 0; - directional_shadow.size = next_power_of_2(GLOBAL_GET("rendering/quality/directional_shadow/size")); - - if (directional_shadow.size > storage->config.max_viewport_dimensions[0] || directional_shadow.size > storage->config.max_viewport_dimensions[1]) { - WARN_PRINT("Cannot set directional shadow size larger than maximum hardware supported size of (" + itos(storage->config.max_viewport_dimensions[0]) + ", " + itos(storage->config.max_viewport_dimensions[1]) + "). Setting size to maximum."); - directional_shadow.size = MIN(directional_shadow.size, storage->config.max_viewport_dimensions[0]); - directional_shadow.size = MIN(directional_shadow.size, storage->config.max_viewport_dimensions[1]); - } - - glGenFramebuffers(1, &directional_shadow.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); - - if (storage->config.use_rgba_3d_shadows) { - //maximum compatibility, renderbuffer and RGBA shadow - glGenRenderbuffers(1, &directional_shadow.depth); - glBindRenderbuffer(GL_RENDERBUFFER, directional_shadow.depth); - glRenderbufferStorage(GL_RENDERBUFFER, storage->config.depth_buffer_internalformat, directional_shadow.size, directional_shadow.size); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, directional_shadow.depth); - - glGenTextures(1, &directional_shadow.color); - glBindTexture(GL_TEXTURE_2D, directional_shadow.color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, directional_shadow.size, directional_shadow.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, directional_shadow.color, 0); - } else { - //just a depth buffer - glGenTextures(1, &directional_shadow.depth); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - - glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); - } - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - ERR_PRINT("Directional shadow framebuffer status invalid"); - } - } + directional_shadow_create(); if (storage->config.use_lightmap_filter_bicubic) { state.scene_shader.add_custom_define("#define USE_LIGHTMAP_FILTER_BICUBIC\n"); @@ -4048,6 +4057,12 @@ void RasterizerSceneGLES2::initialize() { void RasterizerSceneGLES2::iteration() { shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); + + const int directional_shadow_size_new = next_power_of_2(int(GLOBAL_GET("rendering/quality/directional_shadow/size"))); + if (directional_shadow_size != directional_shadow_size_new) { + directional_shadow_size = directional_shadow_size_new; + directional_shadow_create(); + } } void RasterizerSceneGLES2::finalize() { @@ -4055,4 +4070,6 @@ void RasterizerSceneGLES2::finalize() { RasterizerSceneGLES2::RasterizerSceneGLES2() { _light_counter = 0; + directional_shadow_size = next_power_of_2(int(GLOBAL_GET("rendering/quality/directional_shadow/size"))); + } diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 4df57d72708..93f4490fe92 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -278,6 +278,10 @@ public: RID_Owner shadow_atlas_owner; + int directional_shadow_size; + + void directional_shadow_create(); + RID shadow_atlas_create(); void shadow_atlas_set_size(RID p_atlas, int p_size); void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index cc747474cc9..0380c53c899 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -79,6 +79,35 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_arra } } +void RasterizerSceneGLES3::directional_shadow_create() { + if (directional_shadow.fbo) { + // Erase existing directional shadow texture to recreate it. + glDeleteTextures(1, &directional_shadow.depth); + glDeleteFramebuffers(1, &directional_shadow.fbo); + + directional_shadow.depth = 0; + directional_shadow.fbo = 0; + } + + directional_shadow.light_count = 0; + directional_shadow.size = next_power_of_2(directional_shadow_size); + glGenFramebuffers(1, &directional_shadow.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); + glGenTextures(1, &directional_shadow.depth); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + ERR_PRINT("Directional shadow framebuffer status invalid"); + } +} + /* SHADOW ATLAS API */ RID RasterizerSceneGLES3::shadow_atlas_create() { @@ -5034,26 +5063,7 @@ void RasterizerSceneGLES3::initialize() { cube_size >>= 1; } - { - //directional light shadow - directional_shadow.light_count = 0; - directional_shadow.size = next_power_of_2(GLOBAL_GET("rendering/quality/directional_shadow/size")); - glGenFramebuffers(1, &directional_shadow.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); - glGenTextures(1, &directional_shadow.depth); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - ERR_PRINT("Directional shadow framebuffer status invalid"); - } - } + directional_shadow_create(); { //spot and omni ubos @@ -5239,6 +5249,13 @@ void RasterizerSceneGLES3::initialize() { void RasterizerSceneGLES3::iteration() { shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); + + const int directional_shadow_size_new = next_power_of_2(int(GLOBAL_GET("rendering/quality/directional_shadow/size"))); + if (directional_shadow_size != directional_shadow_size_new) { + directional_shadow_size = directional_shadow_size_new; + directional_shadow_create(); + } + subsurface_scatter_follow_surface = GLOBAL_GET("rendering/quality/subsurface_scattering/follow_surface"); subsurface_scatter_weight_samples = GLOBAL_GET("rendering/quality/subsurface_scattering/weight_samples"); subsurface_scatter_quality = SubSurfaceScatterQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/quality"))); @@ -5253,6 +5270,7 @@ void RasterizerSceneGLES3::finalize() { } RasterizerSceneGLES3::RasterizerSceneGLES3() { + directional_shadow_size = next_power_of_2(int(GLOBAL_GET("rendering/quality/directional_shadow/size"))); } RasterizerSceneGLES3::~RasterizerSceneGLES3() { diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index d3a0fd09ba1..74adab7fa65 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -268,6 +268,9 @@ public: RID_Owner shadow_atlas_owner; + int directional_shadow_size; + + void directional_shadow_create(); RID shadow_atlas_create(); void shadow_atlas_set_size(RID p_atlas, int p_size); void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision); diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index f9d39338c40..4da5e7fc045 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2599,7 +2599,7 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600); ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::REAL, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); - GLOBAL_DEF_RST("rendering/quality/directional_shadow/size", 4096); + GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096); GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384")); GLOBAL_DEF_RST("rendering/quality/shadow_atlas/size", 4096);