ui: fix z indices and depth calculations
This commit is contained in:
parent
2929197d9b
commit
db665b96c0
@ -11,6 +11,20 @@ pub struct Camera {
|
|||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
#[property(ignore)]
|
#[property(ignore)]
|
||||||
pub window: WindowId,
|
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)]
|
#[derive(Default)]
|
||||||
@ -55,8 +69,11 @@ pub fn camera_system<T: CameraProjection + Component>(
|
|||||||
|
|
||||||
for (mut camera, mut camera_projection) in &mut query.iter() {
|
for (mut camera, mut camera_projection) in &mut query.iter() {
|
||||||
if let Some(window) = windows.get(camera.window) {
|
if let Some(window) = windows.get(camera.window) {
|
||||||
camera_projection.update(window.width as usize, window.height as usize);
|
if changed_window_ids.contains(&window.id) {
|
||||||
camera.projection_matrix = camera_projection.get_projection_matrix();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
use bevy_math::{Mat4, PerspectiveRh};
|
use bevy_math::{Mat4, PerspectiveRh};
|
||||||
use bevy_property::{Properties, Property};
|
use bevy_property::{Properties, Property};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use super::DepthCalculation;
|
||||||
|
|
||||||
pub trait CameraProjection {
|
pub trait CameraProjection {
|
||||||
fn get_projection_matrix(&self) -> Mat4;
|
fn get_projection_matrix(&self) -> Mat4;
|
||||||
fn update(&mut self, width: usize, height: usize);
|
fn update(&mut self, width: usize, height: usize);
|
||||||
|
fn depth_calculation(&self) -> DepthCalculation;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Properties)]
|
#[derive(Debug, Clone, Properties)]
|
||||||
@ -23,6 +25,10 @@ impl CameraProjection for PerspectiveProjection {
|
|||||||
fn update(&mut self, width: usize, height: usize) {
|
fn update(&mut self, width: usize, height: usize) {
|
||||||
self.aspect_ratio = width as f32 / height as f32;
|
self.aspect_ratio = width as f32 / height as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn depth_calculation(&self) -> DepthCalculation {
|
||||||
|
DepthCalculation::Distance
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PerspectiveProjection {
|
impl Default for PerspectiveProjection {
|
||||||
@ -84,6 +90,10 @@ impl CameraProjection for OrthographicProjection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn depth_calculation(&self) -> DepthCalculation {
|
||||||
|
DepthCalculation::ZDifference
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for OrthographicProjection {
|
impl Default for OrthographicProjection {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use super::Camera;
|
use super::{Camera, DepthCalculation};
|
||||||
use crate::Draw;
|
use crate::Draw;
|
||||||
use bevy_core::FloatOrd;
|
use bevy_core::FloatOrd;
|
||||||
use bevy_ecs::{Entity, Query};
|
use bevy_ecs::{Entity, Query};
|
||||||
@ -26,7 +26,7 @@ pub fn visible_entities_system(
|
|||||||
mut draw_query: Query<(Entity, &Draw)>,
|
mut draw_query: Query<(Entity, &Draw)>,
|
||||||
draw_transform_query: Query<(&Draw, &Transform)>,
|
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();
|
visible_entities.value.clear();
|
||||||
let camera_position = camera_transform.value.w_axis().truncate();
|
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 order = if let Ok(transform) = draw_transform_query.get::<Transform>(entity) {
|
||||||
let position = transform.value.w_axis().truncate();
|
let position = transform.value.w_axis().truncate();
|
||||||
// smaller distances are sorted to lower indices by using the distance from the camera
|
// 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 {
|
} else {
|
||||||
let order = FloatOrd(no_transform_order);
|
let order = FloatOrd(no_transform_order);
|
||||||
no_transform_order += 0.1;
|
no_transform_order += 0.1;
|
||||||
|
|||||||
@ -32,15 +32,20 @@ use update::ui_z_system;
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct UiPlugin;
|
pub struct UiPlugin;
|
||||||
|
|
||||||
|
pub mod stage {
|
||||||
|
pub const UI: &'static str = "ui";
|
||||||
|
}
|
||||||
|
|
||||||
impl AppPlugin for UiPlugin {
|
impl AppPlugin for UiPlugin {
|
||||||
fn build(&self, app: &mut AppBuilder) {
|
fn build(&self, app: &mut AppBuilder) {
|
||||||
app.init_resource::<FlexSurface>()
|
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 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(stage::UI, widget::text_system.system())
|
||||||
.add_system_to_stage_front(stage::POST_UPDATE, ui_z_system.system())
|
.add_system_to_stage(stage::UI, widget::image_node_system.system())
|
||||||
.add_system_to_stage_front(stage::POST_UPDATE, widget::text_system.system())
|
.add_system_to_stage(stage::UI, ui_z_system.system())
|
||||||
.add_system_to_stage_front(stage::POST_UPDATE, widget::image_node_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());
|
.add_system_to_stage(bevy_render::stage::DRAW, widget::draw_text_system.system());
|
||||||
|
|
||||||
let resources = app.resources();
|
let resources = app.resources();
|
||||||
|
|||||||
@ -3,10 +3,17 @@ use bevy_asset::{Assets, Handle};
|
|||||||
use bevy_ecs::Resources;
|
use bevy_ecs::Resources;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::ActiveCameras,
|
camera::ActiveCameras,
|
||||||
|
pass::{
|
||||||
|
LoadOp, Operations, PassDescriptor, RenderPassColorAttachmentDescriptor,
|
||||||
|
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
|
||||||
|
},
|
||||||
pipeline::*,
|
pipeline::*,
|
||||||
render_graph::{base, CameraNode, PassNode, RenderGraph, RenderResourcesNode, WindowSwapChainNode, WindowTextureNode},
|
render_graph::{
|
||||||
|
base, CameraNode, PassNode, RenderGraph, RenderResourcesNode, WindowSwapChainNode,
|
||||||
|
WindowTextureNode,
|
||||||
|
},
|
||||||
shader::{Shader, ShaderStage, ShaderStages},
|
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> =
|
pub const UI_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
|
||||||
@ -121,11 +128,9 @@ impl UiRenderGraphBuilder for RenderGraph {
|
|||||||
|
|
||||||
// setup ui camera
|
// setup ui camera
|
||||||
self.add_system_node(node::UI_CAMERA, CameraNode::new(camera::UI_CAMERA));
|
self.add_system_node(node::UI_CAMERA, CameraNode::new(camera::UI_CAMERA));
|
||||||
self.add_node_edge(node::UI_CAMERA, node::UI_PASS)
|
self.add_node_edge(node::UI_CAMERA, node::UI_PASS).unwrap();
|
||||||
.unwrap();
|
|
||||||
self.add_system_node(node::NODE, RenderResourcesNode::<Node>::new(true));
|
self.add_system_node(node::NODE, RenderResourcesNode::<Node>::new(true));
|
||||||
self.add_node_edge(node::NODE, node::UI_PASS)
|
self.add_node_edge(node::NODE, node::UI_PASS).unwrap();
|
||||||
.unwrap();
|
|
||||||
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
|
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
|
||||||
active_cameras.add(camera::UI_CAMERA);
|
active_cameras.add(camera::UI_CAMERA);
|
||||||
self
|
self
|
||||||
|
|||||||
@ -12,7 +12,7 @@ pub fn ui_z_system(
|
|||||||
mut node_query: Query<(Entity, &Node, &mut LocalTransform)>,
|
mut node_query: Query<(Entity, &Node, &mut LocalTransform)>,
|
||||||
children_query: Query<&Children>,
|
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
|
// 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())
|
let root_nodes = (&mut root_node_query.iter())
|
||||||
@ -24,11 +24,11 @@ pub fn ui_z_system(
|
|||||||
&children_query,
|
&children_query,
|
||||||
&mut node_query,
|
&mut node_query,
|
||||||
entity,
|
entity,
|
||||||
Some(window_z),
|
Some(current_global_z),
|
||||||
Some(window_z),
|
Some(current_global_z),
|
||||||
&mut update_node_entity,
|
&mut update_node_entity,
|
||||||
) {
|
) {
|
||||||
window_z = result;
|
current_global_z = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,18 +36,20 @@ pub fn ui_z_system(
|
|||||||
fn update_node_entity(
|
fn update_node_entity(
|
||||||
node_query: &mut Query<(Entity, &Node, &mut LocalTransform)>,
|
node_query: &mut Query<(Entity, &Node, &mut LocalTransform)>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
_parent_result: Option<f32>,
|
parent_result: Option<f32>,
|
||||||
previous_result: Option<f32>,
|
previous_result: Option<f32>,
|
||||||
) -> Option<f32> {
|
) -> Option<f32> {
|
||||||
let mut transform = node_query.get_mut::<LocalTransform>(entity).unwrap();
|
let mut transform = node_query.get_mut::<LocalTransform>(entity).unwrap();
|
||||||
let mut z = UI_Z_STEP;
|
let mut z = UI_Z_STEP;
|
||||||
if let Some(previous_z) = previous_result {
|
let parent_global_z = parent_result.unwrap();
|
||||||
z += previous_z;
|
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();
|
let mut position = transform.w_axis();
|
||||||
position.set_z(z);
|
position.set_z(z);
|
||||||
transform.set_w_axis(position);
|
transform.set_w_axis(position);
|
||||||
|
|
||||||
return Some(z);
|
return Some(global_z);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user