You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-12-01 16:38:31 +00:00
Shadow volume culling and tighter shadow caster culling
Existing shadow caster culling using the BVH takes no account of the camera. This PR adds the highly encapsulated class VisualServerLightCuller which can cut down the casters in the shadow volume to only those which can cast shadows on the camera frustum. This is used to: * More accurately defer dirty updates to shadows when the shadow volume does not intersect the camera frustum. * Tighter cull shadow casters to the view frustum. Lights dirty state is now automatically managed: * Continuous (tighter caster culling) * Static (all casters are rendered)
This commit is contained in:
@@ -43,6 +43,8 @@
|
||||
#include "portals/portal_renderer.h"
|
||||
#include "servers/arvr/arvr_interface.h"
|
||||
|
||||
class VisualServerLightCuller;
|
||||
|
||||
class VisualServerScene {
|
||||
public:
|
||||
enum {
|
||||
@@ -484,16 +486,60 @@ public:
|
||||
RID instance;
|
||||
uint64_t last_version;
|
||||
List<Instance *>::Element *D; // directional light in scenario
|
||||
|
||||
bool shadow_dirty;
|
||||
|
||||
List<PairInfo> geometries;
|
||||
|
||||
Instance *baked_light;
|
||||
int32_t previous_room_id_hint;
|
||||
|
||||
private:
|
||||
// Instead of a single dirty flag, we maintain a count
|
||||
// so that we can detect lights that are being made dirty
|
||||
// each frame, and switch on tighter caster culling.
|
||||
int32_t shadow_dirty_count;
|
||||
|
||||
uint32_t light_update_frame_id;
|
||||
bool light_intersects_multiple_cameras;
|
||||
uint32_t light_intersects_multiple_cameras_timeout_frame_id;
|
||||
|
||||
public:
|
||||
bool is_shadow_dirty() const { return shadow_dirty_count != 0; }
|
||||
void make_shadow_dirty() { shadow_dirty_count = light_intersects_multiple_cameras ? 1 : 2; }
|
||||
void detect_light_intersects_multiple_cameras(uint32_t p_frame_id) {
|
||||
// We need to detect the case where shadow updates are occurring
|
||||
// more than once per frame. In this case, we need to turn off
|
||||
// tighter caster culling, so situation reverts to one full shadow update
|
||||
// per frame (light_intersects_multiple_cameras is set).
|
||||
if (p_frame_id == light_update_frame_id) {
|
||||
light_intersects_multiple_cameras = true;
|
||||
light_intersects_multiple_cameras_timeout_frame_id = p_frame_id + 60;
|
||||
} else {
|
||||
// When shadow_volume_intersects_multiple_cameras is set, we
|
||||
// want to detect the situation this is no longer the case, via a timeout.
|
||||
// The system can go back to tighter caster culling in this situation.
|
||||
// Having a long-ish timeout prevents rapid cycling.
|
||||
if (light_intersects_multiple_cameras && (p_frame_id >= light_intersects_multiple_cameras_timeout_frame_id)) {
|
||||
light_intersects_multiple_cameras = false;
|
||||
light_intersects_multiple_cameras_timeout_frame_id = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
light_update_frame_id = p_frame_id;
|
||||
}
|
||||
|
||||
void decrement_shadow_dirty() {
|
||||
shadow_dirty_count--;
|
||||
DEV_ASSERT(shadow_dirty_count >= 0);
|
||||
}
|
||||
|
||||
// Shadow updates can either full (everything in the shadow volume)
|
||||
// or closely culled to the camera frustum.
|
||||
bool is_shadow_update_full() const { return shadow_dirty_count == 0; }
|
||||
|
||||
InstanceLightData() {
|
||||
shadow_dirty = true;
|
||||
shadow_dirty_count = 1;
|
||||
light_update_frame_id = UINT32_MAX;
|
||||
light_intersects_multiple_cameras_timeout_frame_id = UINT32_MAX;
|
||||
light_intersects_multiple_cameras = false;
|
||||
|
||||
D = nullptr;
|
||||
last_version = 0;
|
||||
baked_light = nullptr;
|
||||
@@ -623,6 +669,7 @@ public:
|
||||
RID light_instance_cull_result[MAX_LIGHTS_CULLED];
|
||||
int light_cull_count;
|
||||
int directional_light_count;
|
||||
VisualServerLightCuller *light_culler;
|
||||
RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED];
|
||||
int reflection_probe_cull_count;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user