diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 365a3a3b847f..0e5b8d38bf76 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1377,7 +1377,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 09d222baaa1b..b7a02abb39d2 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() { @@ -4014,56 +4072,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"); @@ -4076,6 +4085,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() { @@ -4083,6 +4098,8 @@ void RasterizerSceneGLES2::finalize() { RasterizerSceneGLES2::RasterizerSceneGLES2() { _light_counter = 0; + directional_shadow_size = next_power_of_2(int(GLOBAL_GET("rendering/quality/directional_shadow/size"))); + } RasterizerSceneGLES2::~RasterizerSceneGLES2() { diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index ac8b4250b48a..d3dfafbcf3ce 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 4465feb9ba52..90b4e7c7efe2 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() { @@ -5059,26 +5088,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 @@ -5268,6 +5278,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"))); @@ -5282,6 +5299,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 02d99426d73d..f7dd0fd9e54a 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 b788bba180b3..c96c6377370e 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2616,7 +2616,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);