Add incremental update mode to sky

This commit is contained in:
clayjohn 2020-07-10 17:07:30 -07:00
parent 0fa165f0c9
commit a54f93c169
7 changed files with 82 additions and 32 deletions

View File

@ -3431,10 +3431,10 @@
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_GI_BUFFER" value="17" enum="ViewportDebugDraw">
</constant>
<constant name="SKY_MODE_QUALITY" value="0" enum="SkyMode">
<constant name="SKY_MODE_QUALITY" value="1" enum="SkyMode">
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].
</constant>
<constant name="SKY_MODE_REALTIME" value="1" enum="SkyMode">
<constant name="SKY_MODE_REALTIME" value="3" enum="SkyMode">
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].
</constant>

View File

@ -48,11 +48,17 @@
<constant name="RADIANCE_SIZE_MAX" value="7" enum="RadianceSize">
Represents the size of the [enum RadianceSize] enum.
</constant>
<constant name="PROCESS_MODE_QUALITY" value="0" enum="ProcessMode">
<constant name="PROCESS_MODE_AUTOMATIC" value="0" enum="ProcessMode">
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].
</constant>
<constant name="PROCESS_MODE_QUALITY" value="1" enum="ProcessMode">
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].
</constant>
<constant name="PROCESS_MODE_REALTIME" value="1" enum="ProcessMode">
Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times.
<constant name="PROCESS_MODE_INCREMENTAL" value="2" enum="ProcessMode">
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.
</constant>
<constant name="PROCESS_MODE_REALTIME" value="3" enum="ProcessMode">
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].
</constant>
</constants>

View File

@ -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();
}

View File

@ -51,7 +51,9 @@ public:
};
enum ProcessMode {
PROCESS_MODE_AUTOMATIC,
PROCESS_MODE_QUALITY,
PROCESS_MODE_INCREMENTAL,
PROCESS_MODE_REALTIME
};

View File

@ -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++;
}
}
}

View File

@ -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

View File

@ -720,7 +720,9 @@ public:
/* SKY API */
enum SkyMode {
SKY_MODE_AUTOMATIC,
SKY_MODE_QUALITY,
SKY_MODE_INCREMENTAL,
SKY_MODE_REALTIME
};