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:
parent
b0cd38b7e3
commit
7d60d68c7e
|
@ -1451,6 +1451,9 @@
|
||||||
<member name="rendering/quality/shadows/filter_mode.mobile" type="int" setter="" getter="" default="0">
|
<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.
|
Lower-end override for [member rendering/quality/shadows/filter_mode] on mobile devices, due to performance concerns or driver support.
|
||||||
</member>
|
</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">
|
<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).
|
Forces [MeshInstance] to always perform skinning on the CPU (applies to both GLES2 and GLES3).
|
||||||
See also [member rendering/quality/skinning/software_skinning_fallback].
|
See also [member rendering/quality/skinning/software_skinning_fallback].
|
||||||
|
|
|
@ -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];
|
RID *directional_light_ptr = &light_instance_cull_result[light_cull_count];
|
||||||
directional_light_count = 0;
|
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());
|
Instance **lights_with_shadow = (Instance **)alloca(sizeof(Instance *) * scenario->directional_lights.size());
|
||||||
int directional_shadow_count = 0;
|
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++) {
|
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);
|
_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;
|
if (shadow_map_update != ShadowMapUpdate::SHADOW_MAP_UPDATE_DIRECTIONAL) {
|
||||||
//sorter.sort(light_cull_result,light_cull_count);
|
// Set up point light shadow maps.
|
||||||
|
|
||||||
for (int i = 0; i < light_cull_count; i++) {
|
for (int i = 0; i < light_cull_count; i++) {
|
||||||
Instance *ins = light_cull_result[i];
|
Instance *ins = light_cull_result[i];
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,12 @@ public:
|
||||||
MAX_EXTERIOR_PORTALS = 128,
|
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;
|
uint64_t render_pass;
|
||||||
static VisualServerScene *singleton;
|
static VisualServerScene *singleton;
|
||||||
|
|
||||||
|
@ -508,6 +514,7 @@ public:
|
||||||
int directional_light_count;
|
int directional_light_count;
|
||||||
RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED];
|
RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED];
|
||||||
int reflection_probe_cull_count;
|
int reflection_probe_cull_count;
|
||||||
|
ShadowMapUpdate shadow_map_update = ShadowMapUpdate::SHADOW_MAP_UPDATE_POINT_AND_DIRECTIONAL;
|
||||||
|
|
||||||
RID_Owner<Instance> instance_owner;
|
RID_Owner<Instance> instance_owner;
|
||||||
|
|
||||||
|
|
|
@ -2635,6 +2635,7 @@ VisualServer::VisualServer() {
|
||||||
GLOBAL_DEF("rendering/quality/shadows/filter_mode", 1);
|
GLOBAL_DEF("rendering/quality/shadows/filter_mode", 1);
|
||||||
GLOBAL_DEF("rendering/quality/shadows/filter_mode.mobile", 0);
|
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"));
|
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", true);
|
||||||
GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections.mobile", false);
|
GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections.mobile", false);
|
||||||
|
|
Loading…
Reference in a new issue