From 4ba2f725729c26e2891c8977b30cc944f205e8f4 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Wed, 24 Jun 2020 11:35:01 -0700 Subject: [PATCH] render: is_transparent flag. draw transparent object back-to-front and opaque objects front-to-back --- crates/bevy_core/src/float_ord.rs | 8 +++++++ .../src/camera/visible_entities.rs | 23 +++++++++++++++---- crates/bevy_render/src/draw.rs | 2 ++ .../src/render_graph/nodes/pass_node.rs | 2 +- crates/bevy_sprite/src/entity.rs | 10 ++++++-- examples/3d/texture.rs | 20 ++++++++++++---- 6 files changed, 53 insertions(+), 12 deletions(-) diff --git a/crates/bevy_core/src/float_ord.rs b/crates/bevy_core/src/float_ord.rs index 7a02e85fc7..e23ea1cd9a 100644 --- a/crates/bevy_core/src/float_ord.rs +++ b/crates/bevy_core/src/float_ord.rs @@ -2,6 +2,7 @@ use crate::bytes::AsBytes; use std::{ cmp::Ordering, hash::{Hash, Hasher}, + ops::Neg, }; // working around the famous "rust float ordering" problem @@ -39,3 +40,10 @@ impl Hash for FloatOrd { state.write(self.0.as_bytes()); } } + +impl Neg for FloatOrd { + type Output = FloatOrd; + fn neg(self) -> Self::Output { + FloatOrd(-self.0) + } +} \ No newline at end of file diff --git a/crates/bevy_render/src/camera/visible_entities.rs b/crates/bevy_render/src/camera/visible_entities.rs index 8da50ee2aa..09779d8700 100644 --- a/crates/bevy_render/src/camera/visible_entities.rs +++ b/crates/bevy_render/src/camera/visible_entities.rs @@ -35,6 +35,7 @@ pub fn visible_entities_system( let camera_position = camera_transform.value.w_axis().truncate(); let mut no_transform_order = 0.0; + let mut transparent_entities = Vec::new(); for (entity, draw) in entities_query.iter_entities(world) { if !draw.is_visible { continue; @@ -49,14 +50,28 @@ pub fn visible_entities_system( no_transform_order += 0.1; order }; - visible_entities.value.push(VisibleEntity { - entity, - order, - }) + + if draw.is_transparent { + transparent_entities.push(VisibleEntity { + entity, + order, + }) + } else { + visible_entities.value.push(VisibleEntity { + entity, + order, + }) + } } + + // sort opaque entities front-to-back visible_entities.value.sort_by_key(|e| e.order); + // sort transparent entities front-to-back + transparent_entities.sort_by_key(|e|-e.order); + visible_entities.value.extend(transparent_entities); + // TODO: check for big changes in visible entities len() vs capacity() (ex: 2x) and resize to prevent holding unneeded memory } } diff --git a/crates/bevy_render/src/draw.rs b/crates/bevy_render/src/draw.rs index 635cc2d48a..f7bfc39cbb 100644 --- a/crates/bevy_render/src/draw.rs +++ b/crates/bevy_render/src/draw.rs @@ -51,6 +51,7 @@ pub enum RenderCommand { #[derive(Properties)] pub struct Draw { pub is_visible: bool, + pub is_transparent: bool, #[property(ignore)] pub render_commands: Vec, } @@ -59,6 +60,7 @@ impl Default for Draw { fn default() -> Self { Self { is_visible: true, + is_transparent: false, render_commands: Default::default(), } } diff --git a/crates/bevy_render/src/render_graph/nodes/pass_node.rs b/crates/bevy_render/src/render_graph/nodes/pass_node.rs index ca7f20e41c..75da79fd6e 100644 --- a/crates/bevy_render/src/render_graph/nodes/pass_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/pass_node.rs @@ -103,7 +103,7 @@ impl Node for PassNode { }; let mut draw_state = DrawState::default(); - for visible_entity in visible_entities.iter().rev() { + for visible_entity in visible_entities.iter() { let draw = if let Some(draw) = world.get_component::(visible_entity.entity) { draw } else { diff --git a/crates/bevy_sprite/src/entity.rs b/crates/bevy_sprite/src/entity.rs index 0d505d24de..b021fae8aa 100644 --- a/crates/bevy_sprite/src/entity.rs +++ b/crates/bevy_sprite/src/entity.rs @@ -46,9 +46,12 @@ impl Default for SpriteEntity { ..Default::default() }, )]), + draw: Draw { + is_transparent: true, + ..Default::default() + }, sprite: Default::default(), material: Default::default(), - draw: Default::default(), transform: Default::default(), translation: Default::default(), rotation: Default::default(), @@ -91,10 +94,13 @@ impl Default for SpriteSheetEntity { ..Default::default() }, )]), + draw: Draw { + is_transparent: true, + ..Default::default() + }, mesh: QUAD_HANDLE, sprite: Default::default(), texture_atlas: Default::default(), - draw: Default::default(), transform: Default::default(), translation: Default::default(), rotation: Default::default(), diff --git a/examples/3d/texture.rs b/examples/3d/texture.rs index 5b5a167928..7a0ee2d235 100644 --- a/examples/3d/texture.rs +++ b/examples/3d/texture.rs @@ -31,6 +31,7 @@ fn setup( // this material renders the texture normally let material_handle = materials.add(StandardMaterial { albedo_texture: Some(texture_handle), + shaded: false, ..Default::default() }); @@ -38,6 +39,7 @@ fn setup( let red_material_handle = materials.add(StandardMaterial { albedo: Color::rgba(1.0, 0.0, 0.0, 0.5), albedo_texture: Some(texture_handle), + shaded: false, ..Default::default() }); @@ -45,6 +47,7 @@ fn setup( let blue_material_handle = materials.add(StandardMaterial { albedo: Color::rgba(0.0, 0.0, 1.0, 0.5), albedo_texture: Some(texture_handle), + shaded: false, ..Default::default() }); @@ -57,6 +60,10 @@ fn setup( material: material_handle, translation: Translation::new(0.0, -1.5, 0.0), rotation: Rotation::from_euler_angles(0.0, std::f32::consts::PI / 3.0, 0.0), + draw: Draw { + is_transparent: true, + ..Default::default() + }, ..Default::default() }) // textured quad - modulated @@ -65,6 +72,10 @@ fn setup( material: red_material_handle, translation: Translation::new(0.0, 0.0, 0.0), rotation: Rotation::from_euler_angles(0.0, std::f32::consts::PI / 3.0, 0.0), + draw: Draw { + is_transparent: true, + ..Default::default() + }, ..Default::default() }) // textured quad - modulated @@ -73,11 +84,10 @@ fn setup( material: blue_material_handle, translation: Translation::new(0.0, 1.5, 0.0), rotation: Rotation::from_euler_angles(0.0, std::f32::consts::PI / 3.0, 0.0), - ..Default::default() - }) - // light - .add_entity(LightEntity { - translation: Translation::new(0.0, -5.0, 0.0), + draw: Draw { + is_transparent: true, + ..Default::default() + }, ..Default::default() }) // camera