ui: fix z indices and depth calculations

This commit is contained in:
Carter Anderson 2020-07-29 00:28:44 -07:00
parent 2929197d9b
commit db665b96c0
6 changed files with 66 additions and 24 deletions

View file

@ -11,6 +11,20 @@ pub struct Camera {
pub name: Option<String>,
#[property(ignore)]
pub window: WindowId,
#[property(ignore)]
pub depth_calculation: DepthCalculation,
}
#[derive(Debug)]
pub enum DepthCalculation {
Distance,
ZDifference,
}
impl Default for DepthCalculation {
fn default() -> Self {
DepthCalculation::Distance
}
}
#[derive(Default)]
@ -55,8 +69,11 @@ pub fn camera_system<T: CameraProjection + Component>(
for (mut camera, mut camera_projection) in &mut query.iter() {
if let Some(window) = windows.get(camera.window) {
camera_projection.update(window.width as usize, window.height as usize);
camera.projection_matrix = camera_projection.get_projection_matrix();
if changed_window_ids.contains(&window.id) {
camera_projection.update(window.width as usize, window.height as usize);
camera.projection_matrix = camera_projection.get_projection_matrix();
camera.depth_calculation = camera_projection.depth_calculation();
}
}
}
}

View file

@ -1,10 +1,12 @@
use bevy_math::{Mat4, PerspectiveRh};
use bevy_property::{Properties, Property};
use serde::{Deserialize, Serialize};
use super::DepthCalculation;
pub trait CameraProjection {
fn get_projection_matrix(&self) -> Mat4;
fn update(&mut self, width: usize, height: usize);
fn depth_calculation(&self) -> DepthCalculation;
}
#[derive(Debug, Clone, Properties)]
@ -23,6 +25,10 @@ impl CameraProjection for PerspectiveProjection {
fn update(&mut self, width: usize, height: usize) {
self.aspect_ratio = width as f32 / height as f32;
}
fn depth_calculation(&self) -> DepthCalculation {
DepthCalculation::Distance
}
}
impl Default for PerspectiveProjection {
@ -84,6 +90,10 @@ impl CameraProjection for OrthographicProjection {
}
}
}
fn depth_calculation(&self) -> DepthCalculation {
DepthCalculation::ZDifference
}
}
impl Default for OrthographicProjection {

View file

@ -1,4 +1,4 @@
use super::Camera;
use super::{Camera, DepthCalculation};
use crate::Draw;
use bevy_core::FloatOrd;
use bevy_ecs::{Entity, Query};
@ -26,7 +26,7 @@ pub fn visible_entities_system(
mut draw_query: Query<(Entity, &Draw)>,
draw_transform_query: Query<(&Draw, &Transform)>,
) {
for (_camera, camera_transform, mut visible_entities) in &mut camera_query.iter() {
for (camera, camera_transform, mut visible_entities) in &mut camera_query.iter() {
visible_entities.value.clear();
let camera_position = camera_transform.value.w_axis().truncate();
@ -40,7 +40,10 @@ pub fn visible_entities_system(
let order = if let Ok(transform) = draw_transform_query.get::<Transform>(entity) {
let position = transform.value.w_axis().truncate();
// smaller distances are sorted to lower indices by using the distance from the camera
FloatOrd((camera_position - position).length())
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;

View file

@ -32,15 +32,20 @@ use update::ui_z_system;
#[derive(Default)]
pub struct UiPlugin;
pub mod stage {
pub const UI: &'static str = "ui";
}
impl AppPlugin for UiPlugin {
fn build(&self, app: &mut AppBuilder) {
app.init_resource::<FlexSurface>()
.add_system_to_stage(stage::PRE_UPDATE, ui_focus_system.system())
.add_stage_before(bevy_app::stage::POST_UPDATE, stage::UI)
.add_system_to_stage(bevy_app::stage::PRE_UPDATE, ui_focus_system.system())
// add these stages to front because these must run before transform update systems
.add_system_to_stage_front(stage::POST_UPDATE, flex_node_system.system())
.add_system_to_stage_front(stage::POST_UPDATE, ui_z_system.system())
.add_system_to_stage_front(stage::POST_UPDATE, widget::text_system.system())
.add_system_to_stage_front(stage::POST_UPDATE, widget::image_node_system.system())
.add_system_to_stage(stage::UI, widget::text_system.system())
.add_system_to_stage(stage::UI, widget::image_node_system.system())
.add_system_to_stage(stage::UI, ui_z_system.system())
.add_system_to_stage(stage::UI, flex_node_system.system())
.add_system_to_stage(bevy_render::stage::DRAW, widget::draw_text_system.system());
let resources = app.resources();

View file

@ -3,10 +3,17 @@ use bevy_asset::{Assets, Handle};
use bevy_ecs::Resources;
use bevy_render::{
camera::ActiveCameras,
pass::{
LoadOp, Operations, PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
},
pipeline::*,
render_graph::{base, CameraNode, PassNode, RenderGraph, RenderResourcesNode, WindowSwapChainNode, WindowTextureNode},
render_graph::{
base, CameraNode, PassNode, RenderGraph, RenderResourcesNode, WindowSwapChainNode,
WindowTextureNode,
},
shader::{Shader, ShaderStage, ShaderStages},
texture::TextureFormat, prelude::{Color, MainPass}, pass::{RenderPassColorAttachmentDescriptor, PassDescriptor, TextureAttachment, LoadOp, Operations, RenderPassDepthStencilAttachmentDescriptor},
texture::TextureFormat,
};
pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
@ -121,11 +128,9 @@ impl UiRenderGraphBuilder for RenderGraph {
// setup ui camera
self.add_system_node(node::UI_CAMERA, CameraNode::new(camera::UI_CAMERA));
self.add_node_edge(node::UI_CAMERA, node::UI_PASS)
.unwrap();
self.add_node_edge(node::UI_CAMERA, node::UI_PASS).unwrap();
self.add_system_node(node::NODE, RenderResourcesNode::<Node>::new(true));
self.add_node_edge(node::NODE, node::UI_PASS)
.unwrap();
self.add_node_edge(node::NODE, node::UI_PASS).unwrap();
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
active_cameras.add(camera::UI_CAMERA);
self

View file

@ -12,7 +12,7 @@ pub fn ui_z_system(
mut node_query: Query<(Entity, &Node, &mut LocalTransform)>,
children_query: Query<&Children>,
) {
let mut window_z = 0.0;
let mut current_global_z = 0.0;
// PERF: we can probably avoid an allocation here by making root_node_query and node_query non-overlapping
let root_nodes = (&mut root_node_query.iter())
@ -24,11 +24,11 @@ pub fn ui_z_system(
&children_query,
&mut node_query,
entity,
Some(window_z),
Some(window_z),
Some(current_global_z),
Some(current_global_z),
&mut update_node_entity,
) {
window_z = result;
current_global_z = result;
}
}
}
@ -36,18 +36,20 @@ pub fn ui_z_system(
fn update_node_entity(
node_query: &mut Query<(Entity, &Node, &mut LocalTransform)>,
entity: Entity,
_parent_result: Option<f32>,
parent_result: Option<f32>,
previous_result: Option<f32>,
) -> Option<f32> {
let mut transform = node_query.get_mut::<LocalTransform>(entity).unwrap();
let mut z = UI_Z_STEP;
if let Some(previous_z) = previous_result {
z += previous_z;
let parent_global_z = parent_result.unwrap();
if let Some(previous_global_z) = previous_result {
z += previous_global_z - parent_global_z;
};
let global_z = z + parent_global_z;
let mut position = transform.w_axis();
position.set_z(z);
transform.set_w_axis(position);
return Some(z);
return Some(global_z);
}