diff --git a/crates/bevy_render/src/camera/visible_entities.rs b/crates/bevy_render/src/camera/visible_entities.rs index 775f0dc58e10e..e595361adfb1b 100644 --- a/crates/bevy_render/src/camera/visible_entities.rs +++ b/crates/bevy_render/src/camera/visible_entities.rs @@ -1,9 +1,10 @@ use super::{Camera, DepthCalculation}; use crate::Draw; use bevy_core::FloatOrd; -use bevy_ecs::{Entity, Query, With}; +use bevy_ecs::{Entity, Query, With, Without}; +use bevy_math::Vec3; use bevy_property::Properties; -use bevy_transform::prelude::GlobalTransform; +use bevy_transform::prelude::{Children, GlobalTransform, Parent}; #[derive(Debug)] pub struct VisibleEntity { @@ -25,8 +26,8 @@ impl VisibleEntities { pub fn visible_entities_system( mut camera_query: Query<(&Camera, &GlobalTransform, &mut VisibleEntities)>, - draw_query: Query<(Entity, &Draw)>, - draw_transform_query: Query<&GlobalTransform, With>, + draw_orphan_query: Query, With)>, + draw_query: Query<(Entity, &Draw, Option<&Children>, Option<&GlobalTransform>)>, ) { for (camera, camera_global_transform, mut visible_entities) in camera_query.iter_mut() { visible_entities.value.clear(); @@ -34,29 +35,16 @@ pub fn visible_entities_system( let mut no_transform_order = 0.0; let mut transparent_entities = Vec::new(); - for (entity, draw) in draw_query.iter() { - if !draw.is_visible { - continue; - } - - let order = if let Ok(global_transform) = draw_transform_query.get(entity) { - let position = global_transform.translation; - // smaller distances are sorted to lower indices by using the distance from the camera - FloatOrd(match camera.depth_calculation { - DepthCalculation::ZDifference => camera_position.z() - position.z(), - DepthCalculation::Distance => (camera_position - position).length(), - }) - } else { - let order = FloatOrd(no_transform_order); - no_transform_order += 0.1; - order - }; - - if draw.is_transparent { - transparent_entities.push(VisibleEntity { entity, order }) - } else { - visible_entities.value.push(VisibleEntity { entity, order }) - } + for entity in draw_orphan_query.iter() { + recursive_draw_check( + &draw_query, + entity, + camera, + camera_position, + &mut no_transform_order, + &mut transparent_entities, + &mut visible_entities, + ); } // sort opaque entities front-to-back @@ -69,3 +57,57 @@ pub fn visible_entities_system( // TODO: check for big changes in visible entities len() vs capacity() (ex: 2x) and resize to prevent holding unneeded memory } } + +/// Checks if an object is visible, and recursively checks the object's children. +fn recursive_draw_check( + draw_query: &Query<(Entity, &Draw, Option<&Children>, Option<&GlobalTransform>)>, + entity: Entity, + camera: &Camera, + camera_position: Vec3, + no_transform_order: &mut f32, + transparent_entities: &mut Vec, + visible_entities: &mut VisibleEntities, +) { + let (entity, draw, children, global_transform) = if let Ok(result) = draw_query.get(entity) { + result + } else { + return; + }; + + if !draw.is_visible { + return; + } + + let order = if let Some(global_transform) = global_transform { + let position = global_transform.translation; + // smaller distances are sorted to lower indices by using the distance from the camera + FloatOrd(match camera.depth_calculation { + DepthCalculation::ZDifference => camera_position.z() - position.z(), + DepthCalculation::Distance => (camera_position - position).length(), + }) + } else { + let order = FloatOrd(*no_transform_order); + *no_transform_order += 0.1; + order + }; + + if draw.is_transparent { + transparent_entities.push(VisibleEntity { entity, order }) + } else { + visible_entities.value.push(VisibleEntity { entity, order }) + } + + if let Some(children) = children { + for child in children.iter() { + recursive_draw_check( + draw_query, + *child, + camera, + camera_position, + no_transform_order, + transparent_entities, + visible_entities, + ) + } + } +}