Repository: godotengine/godot (language: cpp)

Issue:
Projection::invert fails with `Condition "0.0 == r3[3]" is true`
### Tested versions

Godot Engine v4.4.dev7.official.46c8f8c5c - https://godotengine.org
Metal 3.2 - Forward+ - Using Device #0: Apple - Apple M1 Max (Apple7)


### System information

Godot v4.4.dev7 - macOS Sequoia (15.2.0) - Multi-window, 2 monitors - Metal (Forward+) - integrated Apple M1 Max (Apple7) - Apple M1 Max (10 threads)

### Issue description

Logs are spammed with the following:

```
ERROR: Condition "0.0 == r3[3]" is true.
   at: invert (/Volumes/Data/projects/games/godot/core/math/projection.cpp:758)
ERROR: Condition "0.0 == r3[3]" is true.
   at: invert (/Volumes/Data/projects/games/godot/core/math/projection.cpp:758)
```

### Steps to reproduce

1. Start TPS-Demo
2. Fire weapon so that it hits the ground[^1]
3. Shortly after bullet collides, logs will be spammed with the above errors

![Image](https://github.com/user-attachments/assets/344e5c9e-47e0-4e17-a2c9-9cf26978984f)

[^1]: It doesn't happen on all shots, and appears mostly when hitting the ground

### Minimal reproduction project (MRP)

TPS-Demo is where I observed this behaviour


Discussion / hints:
Oh my, someone that read the issue guidelines! Jokes aside, this seems to be a regression between the 4.4 dev 6 and 4.4 dev 7, i'll bisect right now.
Bisected to #100319, @Flarkk

![Image](https://github.com/user-attachments/assets/994f0c20-d920-4a7d-949f-6c137d1a198c)

I think I messed up the light range and the shadow range in #100319.

Lights with 0 or very small range may break the shadow projection matrix by placing the far plane before the near plane. This is what likely happens in the TPS demo when a bullet collides and the impact light range is animated.

Just pushed a quick draft (#100862). Will test it properly tomorrow - night time here.

Fix patch:
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index a9941141f87a..0b98fc6769e7 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -2510,7 +2510,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 				}
 
 				real_t radius = RSG::light_storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE);
-				real_t z_near = 0.005f;
+				real_t z_near = MIN(0.005f, radius);
 				Projection cm;
 				cm.set_perspective(90, 1, z_near, radius);
 
@@ -2600,7 +2600,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 
 			real_t radius = RSG::light_storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE);
 			real_t angle = RSG::light_storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE);
-			real_t z_near = 0.005f;
+			real_t z_near = MIN(0.005f, radius);
 
 			Projection cm;
 			cm.set_perspective(angle * 2.0, 1.0, z_near, radius);


Test patch: