Skip to content

Instantly share code, notes, and snippets.

@pcwalton
Created February 6, 2024 03:01
Show Gist options
  • Save pcwalton/c10a157285015b9f2ea2a66730aa7425 to your computer and use it in GitHub Desktop.
Save pcwalton/c10a157285015b9f2ea2a66730aa7425 to your computer and use it in GitHub Desktop.
commit acdae9ee7d92c7bfbbe2d560a3e00039ce5a3380
Author: Patrick Walton <pcwalton@mimiga.net>
Date: Mon Feb 5 18:10:52 2024 -0800
wip
diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml
index 8e5e93718..cde746d06 100644
--- a/crates/bevy_transform/Cargo.toml
+++ b/crates/bevy_transform/Cargo.toml
@@ -19,6 +19,7 @@ bevy_math = { path = "../bevy_math", version = "0.12.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.12.0", features = [
"bevy",
] }
+bevy_utils = { path = "../bevy_utils", version = "0.12.0" }
serde = { version = "1", features = ["derive"], optional = true }
thiserror = "1.0"
diff --git a/crates/bevy_transform/src/systems.rs b/crates/bevy_transform/src/systems.rs
index 8f6bac916..d5365b944 100644
--- a/crates/bevy_transform/src/systems.rs
+++ b/crates/bevy_transform/src/systems.rs
@@ -7,6 +7,7 @@ use bevy_ecs::{
system::{Local, ParamSet},
};
use bevy_hierarchy::{Children, Parent};
+use bevy_utils::EntityHashSet;
/// Update [`GlobalTransform`] component of entities that aren't in the hierarchy
///
@@ -54,19 +55,41 @@ pub fn propagate_transforms(
mut orphaned: RemovedComponents<Parent>,
transform_query: Query<(Ref<Transform>, &mut GlobalTransform, Option<&Children>), With<Parent>>,
parent_query: Query<(Entity, Ref<Parent>)>,
+ dirty_roots: Query<Entity, Or<(Changed<Parent>, Changed<Transform>)>>,
mut orphaned_entities: Local<Vec<Entity>>,
) {
orphaned_entities.clear();
orphaned_entities.extend(orphaned.read());
orphaned_entities.sort_unstable();
+
+ let mut dirty_entities = EntityHashSet::default();
+ for mut current in dirty_roots.iter() {
+ while dirty_entities.insert(current) {
+ let Ok((parent, _)) = parent_query.get(current) else {
+ break;
+ };
+ current = parent;
+ }
+ }
+
root_query.par_iter_mut().for_each(
|(entity, children, transform, mut global_transform)| {
+ // If this entire tree is clean, do nothing.
+ if !dirty_entities.contains(&entity) {
+ return;
+ }
+
let changed = transform.is_changed() || global_transform.is_added() || orphaned_entities.binary_search(&entity).is_ok();
if changed {
*global_transform = GlobalTransform::from(*transform);
}
for (child, actual_parent) in parent_query.iter_many(children) {
+ // Don't bother checking children if we know their transform didn't change.
+ if !changed && !dirty_entities.contains(&child) {
+ continue;
+ }
+
assert_eq!(
actual_parent.get(), entity,
"Malformed hierarchy. This probably means that your hierarchy has been improperly maintained, or contains a cycle"
@@ -84,6 +107,7 @@ pub fn propagate_transforms(
&global_transform,
&transform_query,
&parent_query,
+ &dirty_entities,
child,
changed || actual_parent.is_changed(),
);
@@ -113,6 +137,7 @@ unsafe fn propagate_recursive(
With<Parent>,
>,
parent_query: &Query<(Entity, Ref<Parent>)>,
+ dirty_entities: &EntityHashSet<Entity>,
entity: Entity,
mut changed: bool,
) {
@@ -157,6 +182,11 @@ unsafe fn propagate_recursive(
let Some(children) = children else { return };
for (child, actual_parent) in parent_query.iter_many(children) {
+ // Don't bother checking children if we know their transform didn't change.
+ if !changed && !dirty_entities.contains(&child) {
+ continue;
+ }
+
assert_eq!(
actual_parent.get(), entity,
"Malformed hierarchy. This probably means that your hierarchy has been improperly maintained, or contains a cycle"
@@ -171,6 +201,7 @@ unsafe fn propagate_recursive(
&global_matrix,
transform_query,
parent_query,
+ dirty_entities,
child,
changed || actual_parent.is_changed(),
);
diff --git a/examples/tools/scene_viewer/main.rs b/examples/tools/scene_viewer/main.rs
index e80b3965b..3ef3f739b 100644
--- a/examples/tools/scene_viewer/main.rs
+++ b/examples/tools/scene_viewer/main.rs
@@ -8,6 +8,7 @@
//! If you want to hot reload asset changes, enable the `file_watcher` cargo feature.
use bevy::{
+ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
math::Vec3A,
prelude::*,
render::primitives::{Aabb, Sphere},
@@ -44,6 +45,8 @@ fn main() {
CameraControllerPlugin,
SceneViewerPlugin,
MorphViewerPlugin,
+ FrameTimeDiagnosticsPlugin,
+ LogDiagnosticsPlugin::default(),
))
.add_systems(Startup, setup)
.add_systems(PreUpdate, setup_scene_after_load);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment