Add an option to update shadow maps less often

This can be used to improve performance on low-end setups,
at the cost of shadows visibly lagging behind for dynamic lights/objects
when up close.

This option works best with lights that use Reverse Cull Face and a low
negative bias value.

Co-authored-by: Manuele Finocchiaro <m4nu3lf@gmail.com>
This commit is contained in:
Hugo Locurcio 2021-10-23 13:29:33 +02:00
parent b0cd38b7e3
commit 7d60d68c7e
No known key found for this signature in database
GPG key ID: 39E8F8BE30B0A49C
4 changed files with 32 additions and 8 deletions

View file

@ -1451,6 +1451,9 @@
<member name="rendering/quality/shadows/filter_mode.mobile" type="int" setter="" getter="" default="0">
Lower-end override for [member rendering/quality/shadows/filter_mode] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/quality/shadows/update_every_2_frames" type="bool" setter="" getter="" default="false">
If [code]true[/code], directional and point light shadows are only updated every 2 frames instead of being updated every frame. Updates are staggered across frames to avoid stuttering. This improves performance at the cost of shadows updating in a more "choppy" manner, especially at lower framerates. The difference is mainly noticeable with fast-moving lights, especially when close to the camera.
</member>
<member name="rendering/quality/skinning/force_software_skinning" type="bool" setter="" getter="" default="false">
Forces [MeshInstance] to always perform skinning on the CPU (applies to both GLES2 and GLES3).
See also [member rendering/quality/skinning/software_skinning_fallback].

View file

@ -2641,8 +2641,19 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
RID *directional_light_ptr = &light_instance_cull_result[light_cull_count];
directional_light_count = 0;
// directional lights
{
if (bool(GLOBAL_GET("rendering/quality/shadows/update_every_2_frames"))) {
// Toggle between directional and point light shadow updating every frame.
// This update staggering avoids stuttering by splitting CPU/GPU load across frames.
if (shadow_map_update == ShadowMapUpdate::SHADOW_MAP_UPDATE_DIRECTIONAL) {
shadow_map_update = ShadowMapUpdate::SHADOW_MAP_UPDATE_POINT;
} else {
shadow_map_update = ShadowMapUpdate::SHADOW_MAP_UPDATE_DIRECTIONAL;
}
} else {
shadow_map_update = ShadowMapUpdate::SHADOW_MAP_UPDATE_POINT_AND_DIRECTIONAL;
}
{ // directional lights
Instance **lights_with_shadow = (Instance **)alloca(sizeof(Instance *) * scenario->directional_lights.size());
int directional_shadow_count = 0;
@ -2668,17 +2679,19 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
}
}
VSG::scene_render->set_directional_shadow_count(directional_shadow_count);
if (shadow_map_update != ShadowMapUpdate::SHADOW_MAP_UPDATE_POINT) {
VSG::scene_render->set_directional_shadow_count(directional_shadow_count);
for (int i = 0; i < directional_shadow_count; i++) {
_light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario);
for (int i = 0; i < directional_shadow_count; i++) {
_light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario);
}
}
}
{ //setup shadow maps
//SortArray<Instance*,_InstanceLightsort> sorter;
//sorter.sort(light_cull_result,light_cull_count);
if (shadow_map_update != ShadowMapUpdate::SHADOW_MAP_UPDATE_DIRECTIONAL) {
// Set up point light shadow maps.
for (int i = 0; i < light_cull_count; i++) {
Instance *ins = light_cull_result[i];

View file

@ -54,6 +54,12 @@ public:
MAX_EXTERIOR_PORTALS = 128,
};
enum ShadowMapUpdate {
SHADOW_MAP_UPDATE_POINT_AND_DIRECTIONAL, // Update both point and directional light shadows for this frame (default).
SHADOW_MAP_UPDATE_POINT, // Update point light shadows only for this frame.
SHADOW_MAP_UPDATE_DIRECTIONAL, // Update directional light shadows only for this frame.
};
uint64_t render_pass;
static VisualServerScene *singleton;
@ -508,6 +514,7 @@ public:
int directional_light_count;
RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED];
int reflection_probe_cull_count;
ShadowMapUpdate shadow_map_update = ShadowMapUpdate::SHADOW_MAP_UPDATE_POINT_AND_DIRECTIONAL;
RID_Owner<Instance> instance_owner;

View file

@ -2635,6 +2635,7 @@ VisualServer::VisualServer() {
GLOBAL_DEF("rendering/quality/shadows/filter_mode", 1);
GLOBAL_DEF("rendering/quality/shadows/filter_mode.mobile", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/filter_mode", PropertyInfo(Variant::INT, "rendering/quality/shadows/filter_mode", PROPERTY_HINT_ENUM, "Disabled,PCF5,PCF13"));
GLOBAL_DEF("rendering/quality/shadows/update_every_2_frames", false);
GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true);
GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections.mobile", false);