-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Description
Bevy version
0.16.1
What you did
Here is a mini repro:
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<ButtonInput<KeyCode>>,
camera: Query<&SingleCamera>,
mut cameras: Query<(&mut Camera, Has<Disabled>)>
) {
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.
bevy/crates/bevy_render/src/camera/camera.rs
Lines 1133 to 1144 in 383b351
if !camera.is_active { | |
commands.entity(render_entity).remove::<( | |
ExtractedCamera, | |
ExtractedView, | |
RenderVisibleEntities, | |
TemporalJitter, | |
RenderLayers, | |
Projection, | |
NoIndirectDrawing, | |
ViewUniformOffset, | |
)>(); | |
continue; |
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.
pub fn prepare_core_3d_depth_textures( |
So this function will panic as the camera simply does not exist.
I added a Has<Disabled>
filter to query of extract_cameras
and changed the condition here
bevy/crates/bevy_render/src/camera/camera.rs
Line 1133 in 383b351
if !camera.is_active { |
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.