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

Rendering masks #1209

Merged
merged 13 commits into from
Jan 8, 2021
Next Next commit
can group rendering entities with masks
  • Loading branch information
schell committed Jan 7, 2021
commit 8e9e00dfd5f5f5cd934b900920987f3b09de6f22
70 changes: 66 additions & 4 deletions crates/bevy_render/src/camera/visible_entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,84 @@ impl VisibleEntities {
}
}

/// A mask that describes which rendering group an entity belongs to.
/// Cameras with this component will only render entities with a matching
/// mask. In other words, only an entity with a matching camera will be
/// rendered.
#[derive(Debug, Reflect, PartialEq, Eq, PartialOrd, Ord)]
#[reflect(Component)]
pub struct RenderingMask(pub u8);

impl Default for RenderingMask {
fn default() -> Self {
RenderingMask( 0 )
}
}

impl RenderingMask {
schell marked this conversation as resolved.
Show resolved Hide resolved
pub fn group(n: u8) -> Self {
RenderingMask::default().with_group(n)
}

pub fn with_group(mut self, group: u8) -> Self {
self.0 = self.0 | (1 << group);
self
}

pub fn without_group(mut self, group: u8) -> Self {
self.0 = self.0 | (0 << group);
self
}

pub fn matches(&self, other: &RenderingMask) -> bool {
schell marked this conversation as resolved.
Show resolved Hide resolved
(self.0 & other.0) > 0
}
}


#[cfg(test)]
mod rendering_mask_tests {
use super::RenderingMask;

#[test]
fn rendering_mask_sanity() {
// groups match groups
assert!(RenderingMask::group(1).matches(&RenderingMask::group(1)));
// a group of 0 means the mask is just 1 bit
assert!(RenderingMask::group(0).matches(&RenderingMask(1)));
// a mask will match another mask containing any similar groups
assert!(RenderingMask::group(0).with_group(3).matches(&RenderingMask::group(3)));
}
}

pub fn visible_entities_system(
mut camera_query: Query<(&Camera, &GlobalTransform, &mut VisibleEntities)>,
visible_query: Query<(Entity, &Visible)>,
mut camera_query: Query<(&Camera, &GlobalTransform, &mut VisibleEntities, Option<&RenderingMask>)>,
visible_query: Query<(Entity, &Visible, Option<&RenderingMask>)>,
visible_transform_query: Query<&GlobalTransform, With<Visible>>,
) {
for (camera, camera_global_transform, mut visible_entities) in camera_query.iter_mut() {
for (camera, camera_global_transform, mut visible_entities, maybe_camera_mask) 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, visible) in visible_query.iter() {
for (entity, visible, maybe_ent_mask) in visible_query.iter() {
if !visible.is_visible {
continue;
}

if let Some(camera_mask) = maybe_camera_mask {
if let Some(entity_mask) = maybe_ent_mask {
if !camera_mask.matches(entity_mask) {
continue;
}
} else {
continue;
}
} else if maybe_ent_mask.is_some() {
continue;
}

let order = if let Ok(global_transform) = visible_transform_query.get(entity) {
let position = global_transform.translation;
// smaller distances are sorted to lower indices by using the distance from the camera
Expand Down