Merge pull request #54165 from Calinou/directional-shadow-runtime-change-3.x

Allow changing directional shadow size at run-time
This commit is contained in:
Rémi Verschelde
2022-01-22 15:25:09 +01:00
committed by GitHub
6 changed files with 114 additions and 72 deletions

View File

@ -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() {

View File

@ -278,6 +278,10 @@ public:
RID_Owner<ShadowAtlas> 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);

View File

@ -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() {

View File

@ -268,6 +268,9 @@ public:
RID_Owner<ShadowAtlas> 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);