Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] Add an option to update shadow maps less often #54516

Open
wants to merge 1 commit into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand Down
28 changes: 20 additions & 8 deletions servers/visual/visual_server_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Member

@lawnjelly lawnjelly Apr 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This technique is discouraged to be used every frame, as these string methods are not efficient.

If you look in the comment section at the top of project_settings.h, there are now two methods to only query this when project settings have changed.

From VisualServerScene, as it cannot receive signals, you probably want to cache this value, and call ProjectSettings::has_changes() and only call GLOBAL_GET if changes have occurred.

We can probably centralize this for all such project settings that need to be cached in e.g. VisualServer. If you are not sure how to do this, just remind me after such a change and I can put this in.

We may alternatively be able to use a little macro to do this and store the cached value in a static, much like the WARN_PRINT_ONCE type macros.

// 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;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is just to rotate between 3 modes, we can alternatively just cast to an int and increment then wraparound to zero.

{ // directional lights
Instance **lights_with_shadow = (Instance **)alloca(sizeof(Instance *) * scenario->directional_lights.size());
int directional_shadow_count = 0;

Expand All @@ -2668,17 +2679,18 @@ 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
if (shadow_map_update != ShadowMapUpdate::SHADOW_MAP_UPDATE_DIRECTIONAL) {
// Set up point light shadow maps.

//SortArray<Instance*,_InstanceLightsort> sorter;
//sorter.sort(light_cull_result,light_cull_count);
for (int i = 0; i < light_cull_count; i++) {
Instance *ins = light_cull_result[i];

Expand Down
7 changes: 7 additions & 0 deletions servers/visual/visual_server_scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ class VisualServerScene {
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;

Expand Down Expand Up @@ -508,6 +514,7 @@ class VisualServerScene {
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;

Expand Down
1 change: 1 addition & 0 deletions servers/visual_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down