diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 65c6f6d6d976..726527708449 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 31362045e2b9..4bd9a37b349e 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 4df57d72708f..93f4490fe926 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -278,6 +278,10 @@ class RasterizerSceneGLES2 : public RasterizerScene { 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 cc747474cc9d..0380c53c899d 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 d3a0fd09ba19..74adab7fa658 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -268,6 +268,9 @@ class RasterizerSceneGLES3 : public RasterizerScene { 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 f9d39338c408..4da5e7fc0457 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);