ITADN

Panic in check_dir_light_mesh_visibility after switching to a DirectionalLight with more cascades

#24837ClosedElogain 创建于 2026-07-02
C-BugA-RenderingP-CrashS-Needs-Triage
E
Elogaincommented
## Bevy version and features 0.19.0, default features ## \[Optional\] Relevant system information - rustc 1.96.1, Windows 11 - Not GPU-related — the panic is CPU-side in a visibility system. ## What you did Used two shadow-casting `DirectionalLight`s with different cascade counts at different times: one screen with a 3-cascade light, then a state transition despawns it and another screen spawns 4-cascade lights (bevy default). The lights never exist simultaneously. ```rust // screen A commands.spawn(( DirectionalLight { shadow_maps_enabled: true, ..default() }, CascadeShadowConfigBuilder { num_cascades: 3, ..default() }.build(), DespawnOnExit(GameState::A), )); // screen B, entered later — default config = 4 cascades commands.spawn(DirectionalLight { shadow_maps_enabled: true, ..default() }); ``` ## What went wrong Expected: normal transition. Actual: intermittent panic on the first frames after the transition: ``` thread 'Compute Task Pool (0)' panicked at bevy_light-0.19.0\src\lib.rs:477:57: index out of bounds: the len is 3 but the index is 3 Encountered a panic in system `bevy_light::check_dir_light_mesh_visibility`! ``` ## Additional information Cause (from reading `check_dir_light_mesh_visibility`): the per-thread scratch buffers `view_visible_entities_queue: Local<Parallel<Vec<Vec<Entity>>>>` persist across frames. They are resized to `view_frusta.len()` only inside the `par_iter` per-batch init closure, so a worker thread that receives no batch on a given frame keeps its old buffer size. The collection loop afterwards iterates **all** thread-local buffers and indexes them by the current light's cascade index — a stale 3-slot buffer indexed with cascade 3 of a 4-cascade light panics at line 477 (`thread_entity_queue[view_dest_index]`). Consequences that match observed behavior: - Only triggers going from a smaller cascade count to a larger one (oversized stale buffers are harmless). - Intermittent, since it needs a worker thread to be idle during that frame's parallel iteration. - Same-count lights never trigger it. Workaround: give every shadow-casting `DirectionalLight` the same `num_cascades`. Probable fix: resize/clear the thread-local buffers for all of `Parallel` before the collection loop, or index with `get_mut` and skip/grow stale entries.
关闭于 2026-07-02 2 条评论