Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't render children of entities with is_visible set to false #865

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 69 additions & 27 deletions crates/bevy_render/src/camera/visible_entities.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -25,38 +26,25 @@ 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>>,
draw_orphan_query: Query<Entity, (Without<Parent>, With<Draw>)>,
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();
let camera_position = camera_global_transform.translation;

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
Expand All @@ -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<VisibleEntity>,
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,
)
}
}
}