fix(Spatial/Transforms): fix transform propagation by making bevy entities for all spatials

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2025-08-31 05:08:46 +02:00
parent eac44ded78
commit a14457ecc1
5 changed files with 87 additions and 37 deletions

View File

@@ -57,27 +57,24 @@ fn update_sound_event(
for sound in SOUND_REGISTRY.get_valid_contents() {
if sound.entity.get().is_none() {
let handle = asset_server.load(sound.pending_audio_path.as_path());
sound
.entity
.set(
cmds.spawn((
Name::new("Audio Node"),
SpatialNode(Arc::downgrade(&sound.spatial)),
AudioPlayer::new(handle),
PlaybackSettings {
mode: PlaybackMode::Once,
volume: Volume::Linear(sound.volume),
speed: 1.0,
paused: true,
muted: false,
spatial: true,
spatial_scale: None,
},
))
.id()
.into(),
)
.unwrap();
let entity = cmds
.spawn((
Name::new("Audio Node"),
SpatialNode(Arc::downgrade(&sound.spatial)),
AudioPlayer::new(handle),
PlaybackSettings {
mode: PlaybackMode::Once,
volume: Volume::Linear(sound.volume),
speed: 1.0,
paused: true,
muted: false,
spatial: true,
spatial_scale: None,
},
))
.id();
sound.spatial.set_entity(entity);
sound.entity.set(entity.into()).unwrap();
}
if let Some(sink) = sound.entity.get().and_then(|e| sinks.get(e.0).ok()) {
if sound.play.lock().take().is_some() {

View File

@@ -242,6 +242,7 @@ fn build_line_mesh(
extension: LineExtension { unused: 0 },
})),
));
lines.spatial.set_entity(e.id());
_ = lines.entity.set(e.id().into());
e
}

View File

@@ -243,6 +243,7 @@ fn gen_model_parts(
});
spatial.set_local_transform(transform.compute_matrix());
spatial.set_entity(entity);
cmds.entity(entity)
.insert(SpatialNode(Arc::downgrade(&spatial)));
let mesh_entity = children_query
@@ -570,7 +571,6 @@ impl Model {
);
}
None => {
// TODO: this could be a denail of service vector
let client = self.spatial.node().unwrap().get_client().unwrap();
let part_node = client.scenegraph.add_node(Node::generate(&client, false));
let spatial = Spatial::add_to(

View File

@@ -168,6 +168,7 @@ fn spawn_text(
.add_children(&letters)
.id();
text.entity.lock().replace(EntityHandle(entity));
text.spatial.set_entity(entity);
}
}

View File

@@ -6,6 +6,7 @@ use super::fields::{Field, FieldTrait};
use super::{Aspect, AspectIdentifier};
use crate::bail;
use crate::core::client::Client;
use crate::core::entity_handle::EntityHandle;
use crate::core::error::Result;
use crate::core::registry::Registry;
use crate::nodes::{Node, OWNED_ASPECT_ALIAS_INFO};
@@ -27,11 +28,52 @@ impl Plugin for SpatialNodePlugin {
fn build(&self, app: &mut App) {
app.add_systems(
PostUpdate,
update_spatial_nodes.before(TransformSystem::TransformPropagate),
(
spawn_spatial_nodes,
update_spatial_node_parenting,
update_spatial_nodes,
)
.chain()
.before(TransformSystem::TransformPropagate),
);
}
}
fn spawn_spatial_nodes(mut cmds: Commands) {
for spatial in SPATIAL_REGISTRY
.get_valid_contents()
.into_iter()
.filter(|v| v.entity.lock().is_none())
{
let entity = cmds
.spawn((SpatialNode(Arc::downgrade(&spatial)), Name::new("Spatial")))
.id();
_ = spatial.set_entity(entity);
}
}
fn update_spatial_node_parenting(
query: Query<(Entity, Option<&ChildOf>, &SpatialNode)>,
mut cmds: Commands,
) {
for (entity, parent, spatial) in &query {
let Some(spatial) = spatial.0.upgrade() else {
continue;
};
let parent_entity = spatial
.get_parent()
.and_then(|v| v.entity.lock().as_ref().map(|v| v.0));
// no changes needed, early exit
if parent.map(|v| v.0) == parent_entity {
continue;
}
match parent_entity {
Some(e) => cmds.entity(entity).insert(ChildOf(e)),
None => cmds.entity(entity).remove::<ChildOf>(),
};
}
}
fn update_spatial_nodes(
mut query: Query<(
&mut BevyTransform,
@@ -69,22 +111,25 @@ fn update_spatial_nodes(
}
_ => {}
}
match child_of {
Some(child_of) => {
let Ok(parent) = parent_query.get(child_of.0) else {
warn!("SpatialNode bevy Parent doesn't have global transform");
return;
};
*transform =
BevyTransform::from_matrix(parent.compute_matrix().inverse() * mat4);
}
None => {
*transform = BevyTransform::from_matrix(mat4);
}
}
*transform = BevyTransform::from_matrix(spatial.local_transform());
// match child_of {
// Some(child_of) => {
// let Ok(parent) = parent_query.get(child_of.0) else {
// warn!("SpatialNode bevy Parent doesn't have global transform");
// return;
// };
// *transform =
// BevyTransform::from_matrix(parent.compute_matrix().inverse() * mat4);
// }
// None => {
// *transform = BevyTransform::from_matrix(mat4);
// }
// }
});
}
static SPATIAL_REGISTRY: Registry<Spatial> = Registry::new();
#[derive(Clone, Component, Debug)]
#[require(BevyTransform, Visibility)]
pub struct SpatialNode(pub Weak<Spatial>);
@@ -123,6 +168,7 @@ static ZONEABLE_REGISTRY: Registry<Spatial> = Registry::new();
pub struct Spatial {
pub node: Weak<Node>,
entity: Mutex<Option<EntityHandle>>,
parent: Mutex<Option<Arc<Spatial>>>,
old_parent: Mutex<Option<Arc<Spatial>>>,
transform: Mutex<Mat4>,
@@ -133,8 +179,9 @@ pub struct Spatial {
impl Spatial {
pub fn new(node: Weak<Node>, parent: Option<Arc<Spatial>>, transform: Mat4) -> Arc<Self> {
Arc::new(Spatial {
SPATIAL_REGISTRY.add(Spatial {
node,
entity: Mutex::new(None),
parent: Mutex::new(parent),
old_parent: Mutex::new(None),
transform: Mutex::new(transform),
@@ -143,6 +190,9 @@ impl Spatial {
bounding_box_calc: OnceLock::default(),
})
}
pub fn set_entity(&self, entity: Entity) {
self.entity.lock().replace(entity.into());
}
pub fn add_to(
node: &Arc<Node>,
parent: Option<Arc<Spatial>>,
@@ -396,6 +446,7 @@ impl Drop for Spatial {
fn drop(&mut self) {
zone::release(self);
ZONEABLE_REGISTRY.remove(self);
SPATIAL_REGISTRY.remove(self);
}
}