summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2024-04-05 12:15:53 +0200
committerRémi Verschelde <rverschelde@gmail.com>2024-04-05 12:15:53 +0200
commitb5064a6160f998b009eefc3145c635ca1c89556e (patch)
tree38e6176d92c9677af9c40e4d3f6b0bac51fc9232
parent3a73c04af6ee7f5efd3bbbbbf3735284c2dd10db (diff)
parent70cd25f3eba286efa6149d0ccc267b3fb2cb91d0 (diff)
downloadredot-engine-b5064a6160f998b009eefc3145c635ca1c89556e.tar.gz
Merge pull request #89714 from lawnjelly/tighter_light_cull_colinear_fix
Tighter shadow culling - fix light colinear to frustum edge
-rw-r--r--servers/rendering/rendering_light_culler.cpp18
-rw-r--r--servers/rendering/rendering_light_culler.h33
2 files changed, 45 insertions, 6 deletions
diff --git a/servers/rendering/rendering_light_culler.cpp b/servers/rendering/rendering_light_culler.cpp
index fdf0d73654..0889898f0b 100644
--- a/servers/rendering/rendering_light_culler.cpp
+++ b/servers/rendering/rendering_light_culler.cpp
@@ -427,15 +427,19 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan
uint8_t *entry = &data.LUT_entries[lookup][0];
int n_edges = data.LUT_entry_sizes[lookup] - 1;
+ const Vector3 &pt2 = p_light_source.pos;
+
for (int e = 0; e < n_edges; e++) {
int i0 = entry[e];
int i1 = entry[e + 1];
const Vector3 &pt0 = data.frustum_points[i0];
const Vector3 &pt1 = data.frustum_points[i1];
- // Create plane from 3 points.
- Plane p(pt0, pt1, p_light_source.pos);
- r_cull_planes.add_cull_plane(p);
+ if (!_is_colinear_tri(pt0, pt1, pt2)) {
+ // Create plane from 3 points.
+ Plane p(pt0, pt1, pt2);
+ r_cull_planes.add_cull_plane(p);
+ }
}
// Last to 0 edge.
@@ -446,9 +450,11 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan
const Vector3 &pt0 = data.frustum_points[i0];
const Vector3 &pt1 = data.frustum_points[i1];
- // Create plane from 3 points.
- Plane p(pt0, pt1, p_light_source.pos);
- r_cull_planes.add_cull_plane(p);
+ if (!_is_colinear_tri(pt0, pt1, pt2)) {
+ // Create plane from 3 points.
+ Plane p(pt0, pt1, pt2);
+ r_cull_planes.add_cull_plane(p);
+ }
}
#ifdef LIGHT_CULLER_DEBUG_LOGGING
diff --git a/servers/rendering/rendering_light_culler.h b/servers/rendering/rendering_light_culler.h
index 602543850a..0bf975430b 100644
--- a/servers/rendering/rendering_light_culler.h
+++ b/servers/rendering/rendering_light_culler.h
@@ -163,6 +163,39 @@ private:
bool _prepare_light(const RendererSceneCull::Instance &p_instance, int32_t p_directional_light_id = -1);
+ // Avoid adding extra culling planes derived from near colinear triangles.
+ // The normals derived from these will be inaccurate, and can lead to false
+ // culling of objects that should be within the light volume.
+ bool _is_colinear_tri(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c) const {
+ // Lengths of sides a, b and c.
+ float la = (p_b - p_a).length();
+ float lb = (p_c - p_b).length();
+ float lc = (p_c - p_a).length();
+
+ // Get longest side into lc.
+ if (lb < la) {
+ SWAP(la, lb);
+ }
+ if (lc < lb) {
+ SWAP(lb, lc);
+ }
+
+ // Prevent divide by zero.
+ if (lc > 0.00001f) {
+ // If the summed length of the smaller two
+ // sides is close to the length of the longest side,
+ // the points are colinear, and the triangle is near degenerate.
+ float ld = ((la + lb) - lc) / lc;
+
+ // ld will be close to zero for colinear tris.
+ return ld < 0.00001f;
+ }
+
+ // Don't create planes from tiny triangles,
+ // they won't be accurate.
+ return true;
+ }
+
// Internal version uses LightSource.
bool _add_light_camera_planes(LightCullPlanes &r_cull_planes, const LightSource &p_light_source);