diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 7539f8ff434..85eaac454f4 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -3431,10 +3431,10 @@
-
+
Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant Sky.PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime. If you are finding that the reflection is not blurry enough and is showing sparkles or fireflies, try increasing [member ProjectSettings.rendering/quality/reflections/ggx_samples].
-
+
Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times.
[b]Note:[/b] The fast filtering algorithm is limited to 256x256 cubemaps, so [member Sky.radiance_size] must be set to [constant Sky.RADIANCE_SIZE_256].
diff --git a/doc/classes/Sky.xml b/doc/classes/Sky.xml
index 78c75d9c2bd..a77515b3e61 100644
--- a/doc/classes/Sky.xml
+++ b/doc/classes/Sky.xml
@@ -48,11 +48,17 @@
Represents the size of the [enum RadianceSize] enum.
-
+
+ Automatically selects the appropriate process mode based on your sky shader. If your shader uses [code]TIME[/code] or [code]POSITION[/code], this will use [constant PROCESS_MODE_REALTIME]. If your shader uses any of the [code]LIGHT_*[/code] variables or any custom uniforms, this uses [constant PROCESS_MODE_INCREMENTAL]. Otherwise, this defaults to [constant PROCESS_MODE_QUALITY].
+
+
Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime. If you are finding that the reflection is not blurry enough and is showing sparkles or fireflies, try increasing [member ProjectSettings.rendering/quality/reflections/ggx_samples].
-
- Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times.
+
+ Uses the same high quality importance sampling to process the radiance map as [constant PROCESS_MODE_QUALITY], but updates over several frames. The number of frames is determined by [member ProjectSettings.rendering/quality/reflections/roughness_layers]. Use this when you need highest quality radiance maps, but have a sky that updates slowly.
+
+
+ Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times. If you need better quality, but still need to update the sky every frame, consider turning on [member ProjectSettings.rendering/quality/reflections/fast_filter_high_quality].
[b]Note:[/b] The fast filtering algorithm is limited to 256x256 cubemaps, so [member radiance_size] must be set to [constant RADIANCE_SIZE_256].
diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp
index 38d1346541c..7e32516f94e 100644
--- a/scene/resources/sky.cpp
+++ b/scene/resources/sky.cpp
@@ -83,8 +83,8 @@ void Sky::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material"), &Sky::get_material);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,PanoramaSkyMaterial,ProceduralSkyMaterial,PhysicalSkyMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Automatic,HighQuality,HighQualityIncremental,RealTime"), "set_process_mode", "get_process_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "32,64,128,256,512,1024,2048"), "set_radiance_size", "get_radiance_size");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "HighQuality,RealTime"), "set_process_mode", "get_process_mode");
BIND_ENUM_CONSTANT(RADIANCE_SIZE_32);
BIND_ENUM_CONSTANT(RADIANCE_SIZE_64);
@@ -95,12 +95,14 @@ void Sky::_bind_methods() {
BIND_ENUM_CONSTANT(RADIANCE_SIZE_2048);
BIND_ENUM_CONSTANT(RADIANCE_SIZE_MAX);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_AUTOMATIC);
BIND_ENUM_CONSTANT(PROCESS_MODE_QUALITY);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_INCREMENTAL);
BIND_ENUM_CONSTANT(PROCESS_MODE_REALTIME);
}
Sky::Sky() {
- mode = PROCESS_MODE_QUALITY;
+ mode = PROCESS_MODE_AUTOMATIC;
radiance_size = RADIANCE_SIZE_256;
sky = RS::get_singleton()->sky_create();
}
diff --git a/scene/resources/sky.h b/scene/resources/sky.h
index 37f0a589f94..06704b35eae 100644
--- a/scene/resources/sky.h
+++ b/scene/resources/sky.h
@@ -51,7 +51,9 @@ public:
};
enum ProcessMode {
+ PROCESS_MODE_AUTOMATIC,
PROCESS_MODE_QUALITY,
+ PROCESS_MODE_INCREMENTAL,
PROCESS_MODE_REALTIME
};
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
index dd68011111f..4ebed78996d 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -181,16 +181,14 @@ void RasterizerSceneRD::_create_reflection_importance_sample(ReflectionData &rd,
}
}
-void RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd) {
- if (sky_use_cubemap_array) {
- for (int i = 0; i < rd.layers.size(); i++) {
- for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) {
- for (int k = 0; k < 6; k++) {
- RID view = rd.layers[i].mipmaps[j].views[k];
- RID texture = rd.layers[i].mipmaps[j + 1].views[k];
- Size2i size = rd.layers[i].mipmaps[j + 1].size;
- storage->get_effects()->make_mipmap(view, texture, size);
- }
+void RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end) {
+ for (int i = p_start; i < p_end; i++) {
+ for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) {
+ for (int k = 0; k < 6; k++) {
+ RID view = rd.layers[i].mipmaps[j].views[k];
+ RID texture = rd.layers[i].mipmaps[j + 1].views[k];
+ Size2i size = rd.layers[i].mipmaps[j + 1].size;
+ storage->get_effects()->make_mipmap(view, texture, size);
}
}
}
@@ -1924,6 +1922,7 @@ void RasterizerSceneRD::_update_dirty_skys() {
}
sky->reflection.dirty = true;
+ sky->processing_layer = 0;
Sky *next = sky->dirty_list;
sky->dirty_list = nullptr;
@@ -2276,8 +2275,32 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
float multiplier = environment_get_bg_energy(p_environment);
+ bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
+ RS::SkyMode sky_mode = sky->mode;
+
+ if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
+ if (shader_data->uses_time || shader_data->uses_position) {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_REALTIME;
+ } else if (shader_data->uses_light || shader_data->ubo_size > 0) {
+ update_single_frame = false;
+ sky_mode = RS::SKY_MODE_INCREMENTAL;
+ } else {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+ }
+
+ if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) {
+ // On the first frame after creating sky, rebuild in single frame
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+
+ int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size();
+
// Update radiance cubemap
- if (sky->reflection.dirty) {
+ if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) {
static const Vector3 view_normals[6] = {
Vector3(+1, 0, 0),
Vector3(-1, 0, 0),
@@ -2349,27 +2372,41 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
- if (sky_use_cubemap_array) {
- if (sky->mode == RS::SKY_MODE_QUALITY) {
- for (int i = 1; i < sky->reflection.layers.size(); i++) {
- _create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, i);
- }
- } else {
- _create_reflection_fast_filter(sky->reflection, sky_use_cubemap_array);
- }
- _update_reflection_mipmaps(sky->reflection);
+ if (sky_mode == RS::SKY_MODE_REALTIME) {
+ _create_reflection_fast_filter(sky->reflection, sky_use_cubemap_array);
+ if (sky_use_cubemap_array) {
+ _update_reflection_mipmaps(sky->reflection, 0, sky->reflection.layers.size());
+ }
} else {
- if (sky->mode == RS::SKY_MODE_QUALITY) {
- for (int i = 1; i < sky->reflection.layers[0].mipmaps.size(); i++) {
+ if (update_single_frame) {
+ for (int i = 1; i < max_processing_layer; i++) {
_create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, i);
}
+ if (sky_use_cubemap_array) {
+ _update_reflection_mipmaps(sky->reflection, 0, sky->reflection.layers.size());
+ }
} else {
- _create_reflection_fast_filter(sky->reflection, sky_use_cubemap_array);
+ if (sky_use_cubemap_array) {
+ // Multi-Frame so just update the first array level
+ _update_reflection_mipmaps(sky->reflection, 0, 1);
+ }
}
+ sky->processing_layer = 1;
}
sky->reflection.dirty = false;
+
+ } else {
+ if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
+ _create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, sky->processing_layer);
+
+ if (sky_use_cubemap_array) {
+ _update_reflection_mipmaps(sky->reflection, sky->processing_layer, sky->processing_layer + 1);
+ }
+
+ sky->processing_layer++;
+ }
}
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
index 83c03399ab8..f09f9dde656 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -145,7 +145,7 @@ private:
void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality);
void _create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays);
void _create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer);
- void _update_reflection_mipmaps(ReflectionData &rd);
+ void _update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end);
/* Sky shader */
@@ -261,10 +261,11 @@ private:
int radiance_size = 256;
- RS::SkyMode mode = RS::SKY_MODE_QUALITY;
+ RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC;
ReflectionData reflection;
bool dirty = false;
+ int processing_layer = 0;
Sky *dirty_list = nullptr;
//State to track when radiance cubemap needs updating
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 2e5ceec02f4..109e9e53c56 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -720,7 +720,9 @@ public:
/* SKY API */
enum SkyMode {
+ SKY_MODE_AUTOMATIC,
SKY_MODE_QUALITY,
+ SKY_MODE_INCREMENTAL,
SKY_MODE_REALTIME
};