Bevy crashes when disabling Camera entities
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## Bevy version
0.16.1
## What you did
Here is a mini repro:
```rust
use bevy::{ecs::entity_disabling::Disabled, prelude::*};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, input)
.run();
}
#[derive(Component)]
struct SingleCamera(Entity);
fn setup(mut commands: Commands) {
let camera = commands.spawn((
Camera3d::default(),
Camera {
is_active: true,
..Default::default()
},
// Disabled
)).id();
commands.spawn(SingleCamera(camera));
}
fn input(
mut commands: Commands,
input: Res>,
camera: Query<&SingleCamera>,
mut cameras: Query<(&mut Camera, Has)>
) {
let entity = camera.single().unwrap().0;
let mut camera = cameras.single_mut().unwrap();
if input.just_released(KeyCode::Space) {
// now set is_active to true and insert the "Disabled" component
camera.0.is_active = false;
commands.entity(entity).insert(Disabled);
}
}
```
Run this App and press "Space", there will be a crash with message
```
thread 'Compute Task Pool (4)' panicked at /bevy/crates/bevy_core_pipeline/src/core_3d/mod.rs:833:22:
The depth texture usage should already exist for this target
```
## Additional information
I tried to dig into the source code to figure out what exactly causes this. Here are my findings.
It seems that the components like `ExtractedView` are not automatically cleaned up from render world after each run of render pipeline. This the reason why we need to manually remove them once the corresponding camera becomes inactive.
https://github.com/bevyengine/bevy/blob/383b3510455c431f34cf3f2c6e3c2d40eddce744/crates/bevy_render/src/camera/camera.rs#L1133-L1144
However, when the camera is disabled by a `Disabled` component, it is filtered out from the query, thus makes the extracted components remain in the render world, even we set `camera.is_active` to `false`. However, there are serval tasks like `prepare_core_3d_depth_textures` highly relies on the existence of these extracted components to determine currently active cameras.
https://github.com/bevyengine/bevy/blob/383b3510455c431f34cf3f2c6e3c2d40eddce744/crates/bevy_core_pipeline/src/core_3d/mod.rs#L766
So this function will panic as the camera simply does not exist.
I added a `Has` filter to query of `extract_cameras` and changed the condition here
https://github.com/bevyengine/bevy/blob/383b3510455c431f34cf3f2c6e3c2d40eddce744/crates/bevy_render/src/camera/camera.rs#L1133
to
```
if !camera.is_active || disabled {
```
Then the mini repro works.
P.S. I'm not familiar when bevy's codebase, so my analysis could be wrong. I would appreciate it if someone can correct me.
Contributor guide
Research direction
Reproduce the crash with the Rust mini repro, then inspect extract_cameras in crates/bevy_render/src/camera/camera.rs and prepare_core_3d_depth_textures in crates/bevy_core_pipeline/src/core_3d/mod.rs. Trace how disabling a camera affects extracted render-world components and verify that the repro no longer panics when the camera is disabled.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- computer-graphics, game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100