mirror of
https://github.com/Redot-Engine/redot-engine.git
synced 2025-12-06 07:17:42 -05:00
Jitter raster occlusion camera to reduce false positives.
Due to the low resolution of the occlusion buffer, small gaps between occluders can be closed and incorrectly occlude instances which should show through the gaps. To ameliorate this problem, this PR jitters the occlusion buffer over time, making it more likely an instance will be seen through a gap. This is used in conjunction with an occlusion timer per instance, to prevent instances flickering on and off rapidly.
This commit is contained in:
@@ -536,6 +536,64 @@ void RaycastOcclusionCull::buffer_set_size(RID p_buffer, const Vector2i &p_size)
|
||||
buffers[p_buffer].resize(p_size);
|
||||
}
|
||||
|
||||
Projection RaycastOcclusionCull::_jitter_projection(const Projection &p_cam_projection, const Size2i &p_viewport_size) {
|
||||
if (!_jitter_enabled) {
|
||||
return p_cam_projection;
|
||||
}
|
||||
|
||||
// Prevent divide by zero when using NULL viewport.
|
||||
if ((p_viewport_size.x <= 0) || (p_viewport_size.y <= 0)) {
|
||||
return p_cam_projection;
|
||||
}
|
||||
|
||||
Projection p = p_cam_projection;
|
||||
|
||||
int32_t frame = Engine::get_singleton()->get_frames_drawn();
|
||||
frame %= 9;
|
||||
|
||||
Vector2 jitter;
|
||||
|
||||
switch (frame) {
|
||||
default:
|
||||
break;
|
||||
case 1: {
|
||||
jitter = Vector2(-1, -1);
|
||||
} break;
|
||||
case 2: {
|
||||
jitter = Vector2(1, -1);
|
||||
} break;
|
||||
case 3: {
|
||||
jitter = Vector2(-1, 1);
|
||||
} break;
|
||||
case 4: {
|
||||
jitter = Vector2(1, 1);
|
||||
} break;
|
||||
case 5: {
|
||||
jitter = Vector2(-0.5f, -0.5f);
|
||||
} break;
|
||||
case 6: {
|
||||
jitter = Vector2(0.5f, -0.5f);
|
||||
} break;
|
||||
case 7: {
|
||||
jitter = Vector2(-0.5f, 0.5f);
|
||||
} break;
|
||||
case 8: {
|
||||
jitter = Vector2(0.5f, 0.5f);
|
||||
} break;
|
||||
}
|
||||
|
||||
// The multiplier here determines the divergence from center,
|
||||
// and is to some extent a balancing act.
|
||||
// Higher divergence gives fewer false hidden, but more false shown.
|
||||
// False hidden is obvious to viewer, false shown is not.
|
||||
// False shown can lower percentage that are occluded, and therefore performance.
|
||||
jitter *= Vector2(1 / (float)p_viewport_size.x, 1 / (float)p_viewport_size.y) * 0.05f;
|
||||
|
||||
p.add_jitter_offset(jitter);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal) {
|
||||
if (!buffers.has(p_buffer)) {
|
||||
return;
|
||||
@@ -550,7 +608,9 @@ void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_
|
||||
Scenario &scenario = scenarios[buffer.scenario_rid];
|
||||
scenario.update();
|
||||
|
||||
buffer.update_camera_rays(p_cam_transform, p_cam_projection, p_cam_orthogonal);
|
||||
Projection jittered_proj = _jitter_projection(p_cam_projection, buffer.get_occlusion_buffer_size());
|
||||
|
||||
buffer.update_camera_rays(p_cam_transform, jittered_proj, p_cam_orthogonal);
|
||||
|
||||
scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks.ptr(), buffer.camera_rays_tile_count);
|
||||
buffer.sort_rays(-p_cam_transform.basis.get_column(2), p_cam_orthogonal);
|
||||
@@ -596,6 +656,7 @@ void RaycastOcclusionCull::_init_embree() {
|
||||
RaycastOcclusionCull::RaycastOcclusionCull() {
|
||||
raycast_singleton = this;
|
||||
int default_quality = GLOBAL_GET("rendering/occlusion_culling/bvh_build_quality");
|
||||
_jitter_enabled = GLOBAL_GET("rendering/occlusion_culling/jitter_projection");
|
||||
build_quality = RS::ViewportOcclusionCullingBuildQuality(default_quality);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user