diff --git a/crates/bevy_pbr/src/nodes/lights_node.rs b/crates/bevy_pbr/src/nodes/lights_node.rs index 5d57d295ae..1e73e6819d 100644 --- a/crates/bevy_pbr/src/nodes/lights_node.rs +++ b/crates/bevy_pbr/src/nodes/lights_node.rs @@ -119,7 +119,7 @@ impl SystemNode for LightsNode { query.iter(world).zip(data.chunks_exact_mut(size)) { slot.copy_from_slice( - LightRaw::from(&light, &local_to_world.0, &translation).as_bytes(), + LightRaw::from(&light, &local_to_world.value, &translation).as_bytes(), ); } }, diff --git a/crates/bevy_render/src/entity.rs b/crates/bevy_render/src/entity.rs index 8d1d9fa03a..8c446dadaf 100644 --- a/crates/bevy_render/src/entity.rs +++ b/crates/bevy_render/src/entity.rs @@ -19,6 +19,8 @@ pub struct PerspectiveCameraEntity { pub camera: Camera, pub perspective_projection: PerspectiveProjection, pub local_to_world: LocalToWorld, + pub translation: Translation, + pub rotation: Rotation, } impl Default for PerspectiveCameraEntity { @@ -30,6 +32,8 @@ impl Default for PerspectiveCameraEntity { }, perspective_projection: Default::default(), local_to_world: Default::default(), + translation: Default::default(), + rotation: Default::default(), } } diff --git a/crates/bevy_render/src/render_graph/nodes/camera_node.rs b/crates/bevy_render/src/render_graph/nodes/camera_node.rs index 0b069419b3..4c5e594828 100644 --- a/crates/bevy_render/src/render_graph/nodes/camera_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/camera_node.rs @@ -77,7 +77,7 @@ impl SystemNode for CameraNode { .find(|(camera, _)| camera.name.as_ref().map(|n| n.as_str()) == Some(&uniform_name)) { let camera_matrix: [[f32; 4]; 4] = - (camera.view_matrix * local_to_world.0).to_cols_array_2d(); + (camera.view_matrix * local_to_world.value).to_cols_array_2d(); let tmp_buffer = render_resources.create_buffer_mapped( BufferInfo { diff --git a/crates/bevy_render/src/shader/uniforms/local_to_world.rs b/crates/bevy_render/src/shader/uniforms/local_to_world.rs index 58199c44c0..a83b3b93dc 100644 --- a/crates/bevy_render/src/shader/uniforms/local_to_world.rs +++ b/crates/bevy_render/src/shader/uniforms/local_to_world.rs @@ -55,7 +55,7 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld { fn get_uniform_bytes(&self, name: &str) -> Option> { match name { - "Object" => Some(self.0.get_bytes()), + "Object" => Some(self.value.get_bytes()), _ => None, } } @@ -65,7 +65,7 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld { } fn get_field_bind_type(&self, name: &str) -> Option { match name { - "object" => self.0.get_bind_type(), + "object" => self.value.get_bind_type(), _ => None, } } @@ -75,7 +75,7 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld { fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]> { match name { - "Object" => self.0.get_bytes_ref(), + "Object" => self.value.get_bytes_ref(), _ => None, } } diff --git a/crates/bevy_transform/src/components/local_to_world.rs b/crates/bevy_transform/src/components/local_to_world.rs index 99c0df5db8..e93eb0ebc1 100644 --- a/crates/bevy_transform/src/components/local_to_world.rs +++ b/crates/bevy_transform/src/components/local_to_world.rs @@ -1,16 +1,35 @@ use crate::math::Mat4; -use shrinkwraprs::Shrinkwrap; -use std::fmt; use bevy_property::Properties; +use std::fmt; -#[derive(Shrinkwrap, Debug, PartialEq, Clone, Copy, Properties)] -#[shrinkwrap(mutable)] -pub struct LocalToWorld(pub Mat4); +#[derive(Debug, PartialEq, Clone, Copy, Properties)] +pub struct LocalToWorld { + pub value: Mat4, + pub sync: bool, // NOTE: this is hopefully a temporary measure to allow setting the transform directly. + // ideally setting the transform automatically propagates back to position / translation / rotation, + // but right now they are always considered the source of truth +} impl LocalToWorld { #[inline(always)] pub fn identity() -> Self { - Self(Mat4::identity()) + LocalToWorld { + value: Mat4::identity(), + sync: true, + } + } + + #[inline(always)] + pub fn new(value: Mat4) -> Self { + LocalToWorld { value, sync: true } + } + + /// This creates a new `LocalToWorld` transform with the `sync` field set to `false`. + /// While `sync` is false, position, rotation, and scale components will not be synced to the transform. + /// This is helpful if you want to manually set the transform to a value (ex: Mat4::look_at_rh) + #[inline(always)] + pub fn new_sync_disabled(value: Mat4) -> Self { + LocalToWorld { value, sync: false } } } @@ -22,6 +41,6 @@ impl Default for LocalToWorld { impl fmt::Display for LocalToWorld { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) + write!(f, "{}", self.value) } } diff --git a/crates/bevy_transform/src/local_to_world_propagate_system.rs b/crates/bevy_transform/src/local_to_world_propagate_system.rs index dadff59df0..6723796945 100644 --- a/crates/bevy_transform/src/local_to_world_propagate_system.rs +++ b/crates/bevy_transform/src/local_to_world_propagate_system.rs @@ -39,7 +39,7 @@ fn propagate_recursive( } }; - let new_local_to_world = LocalToWorld(parent_local_to_world.0 * local_to_parent.0); + let new_local_to_world = LocalToWorld { value: parent_local_to_world.value * local_to_parent.0, sync: true }; commands.add_component(entity, new_local_to_world); // Collect children diff --git a/crates/bevy_transform/src/local_to_world_system.rs b/crates/bevy_transform/src/local_to_world_system.rs index 819adc68ff..1073520456 100644 --- a/crates/bevy_transform/src/local_to_world_system.rs +++ b/crates/bevy_transform/src/local_to_world_system.rs @@ -132,31 +132,36 @@ pub fn build(_: &mut World) -> Box { s.spawn(|_| unsafe { // Translation a.for_each_unchecked(world, |(mut ltw, translation)| { - *ltw = LocalToWorld(Mat4::from_translation(translation.0)); + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_translation(translation.0)); }); }); s.spawn(|_| unsafe { // Rotation b.for_each_unchecked(world, |(mut ltw, rotation)| { - *ltw = LocalToWorld(Mat4::from_quat(rotation.0)); + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_quat(rotation.0)); }); }); s.spawn(|_| unsafe { // Scale c.for_each_unchecked(world, |(mut ltw, scale)| { - *ltw = LocalToWorld(Mat4::from_scale(Vec3::new(scale.0, scale.0, scale.0))); + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_scale(Vec3::new(scale.0, scale.0, scale.0))); }); }); s.spawn(|_| unsafe { // NonUniformScale d.for_each_unchecked(world, |(mut ltw, non_uniform_scale)| { - *ltw = LocalToWorld(Mat4::from_scale(non_uniform_scale.0)); + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_scale(non_uniform_scale.0)); }); }); s.spawn(|_| unsafe { // Translation + Rotation e.for_each_unchecked(world, |(mut ltw, translation, rotation)| { - *ltw = LocalToWorld(Mat4::from_rotation_translation( + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_rotation_translation( rotation.0, translation.0, )); @@ -165,7 +170,8 @@ pub fn build(_: &mut World) -> Box { s.spawn(|_| unsafe { // Translation + Scale f.for_each_unchecked(world, |(mut ltw, translation, scale)| { - *ltw = LocalToWorld(Mat4::from_scale_rotation_translation( + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_scale_rotation_translation( Vec3::new(scale.0, scale.0, scale.0), Quat::default(), translation.0, @@ -175,7 +181,8 @@ pub fn build(_: &mut World) -> Box { s.spawn(|_| unsafe { // Translation + NonUniformScale g.for_each_unchecked(world, |(mut ltw, translation, non_uniform_scale)| { - *ltw = LocalToWorld(Mat4::from_scale_rotation_translation( + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_scale_rotation_translation( non_uniform_scale.0, Quat::default(), translation.0, @@ -185,7 +192,8 @@ pub fn build(_: &mut World) -> Box { s.spawn(|_| unsafe { // Rotation + Scale h.for_each_unchecked(world, |(mut ltw, rotation, scale)| { - *ltw = LocalToWorld(Mat4::from_scale_rotation_translation( + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_scale_rotation_translation( Vec3::new(scale.0, scale.0, scale.0), rotation.0, Vec3::default(), @@ -195,7 +203,8 @@ pub fn build(_: &mut World) -> Box { s.spawn(|_| unsafe { // Rotation + NonUniformScale i.for_each_unchecked(world, |(mut ltw, rotation, non_uniform_scale)| { - *ltw = LocalToWorld(Mat4::from_scale_rotation_translation( + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_scale_rotation_translation( non_uniform_scale.0, rotation.0, Vec3::default(), @@ -205,7 +214,8 @@ pub fn build(_: &mut World) -> Box { s.spawn(|_| unsafe { // Translation + Rotation + Scale j.for_each_unchecked(world, |(mut ltw, translation, rotation, scale)| { - *ltw = LocalToWorld(Mat4::from_scale_rotation_translation( + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_scale_rotation_translation( Vec3::new(scale.0, scale.0, scale.0), rotation.0, translation.0, @@ -217,7 +227,8 @@ pub fn build(_: &mut World) -> Box { k.for_each_unchecked( world, |(mut ltw, translation, rotation, non_uniform_scale)| { - *ltw = LocalToWorld(Mat4::from_scale_rotation_translation( + if !ltw.sync { return; } + *ltw = LocalToWorld::new(Mat4::from_scale_rotation_translation( non_uniform_scale.0, rotation.0, translation.0, diff --git a/examples/3d/3d_scene.rs b/examples/3d/3d_scene.rs index 3a65b4e113..65ea128520 100644 --- a/examples/3d/3d_scene.rs +++ b/examples/3d/3d_scene.rs @@ -50,7 +50,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(3.0, 8.0, 5.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/3d/load_model.rs b/examples/3d/load_model.rs index 655ef88795..2f2bb15673 100644 --- a/examples/3d/load_model.rs +++ b/examples/3d/load_model.rs @@ -39,7 +39,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(2.0, -6.0, 2.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/3d/parenting.rs b/examples/3d/parenting.rs index 8c1c4b673c..1568df4c38 100644 --- a/examples/3d/parenting.rs +++ b/examples/3d/parenting.rs @@ -53,7 +53,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(5.0, 10.0, 10.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/3d/spawner.rs b/examples/3d/spawner.rs index ba8252b61e..410b1a184f 100644 --- a/examples/3d/spawner.rs +++ b/examples/3d/spawner.rs @@ -63,7 +63,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(3.0, 8.0, 5.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/3d/texture.rs b/examples/3d/texture.rs index ecace1ec24..dc6b652b17 100644 --- a/examples/3d/texture.rs +++ b/examples/3d/texture.rs @@ -67,7 +67,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(3.0, -8.0, 5.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/app/dynamic_plugin_loading/example_plugin/src/lib.rs b/examples/app/dynamic_plugin_loading/example_plugin/src/lib.rs index baf30b8e84..6c4e4a913d 100644 --- a/examples/app/dynamic_plugin_loading/example_plugin/src/lib.rs +++ b/examples/app/dynamic_plugin_loading/example_plugin/src/lib.rs @@ -35,7 +35,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(3.0, 8.0, 5.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/asset/asset_loading.rs b/examples/asset/asset_loading.rs index 4e86ac5bc8..3f67605d95 100644 --- a/examples/asset/asset_loading.rs +++ b/examples/asset/asset_loading.rs @@ -70,7 +70,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(0.0, -10.0, 3.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/asset/hot_asset_reloading.rs b/examples/asset/hot_asset_reloading.rs index dc8f19d9a5..a6d66ebc65 100644 --- a/examples/asset/hot_asset_reloading.rs +++ b/examples/asset/hot_asset_reloading.rs @@ -47,7 +47,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(2.0, -6.0, 2.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/input/input_keyboard.rs b/examples/input/input_keyboard.rs index efef71a53a..61b2584968 100644 --- a/examples/input/input_keyboard.rs +++ b/examples/input/input_keyboard.rs @@ -87,7 +87,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(3.0, 8.0, 5.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/shader/shader_custom_material.rs b/examples/shader/shader_custom_material.rs index 7a7d49746d..68132d8b19 100644 --- a/examples/shader/shader_custom_material.rs +++ b/examples/shader/shader_custom_material.rs @@ -85,7 +85,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(3.0, 8.0, 5.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0), diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index 1cbb89125c..07eab013b4 100644 --- a/examples/shader/shader_defs.rs +++ b/examples/shader/shader_defs.rs @@ -112,7 +112,7 @@ fn setup( }) // camera .add_entity(PerspectiveCameraEntity { - local_to_world: LocalToWorld(Mat4::look_at_rh( + local_to_world: LocalToWorld::new_sync_disabled(Mat4::look_at_rh( Vec3::new(3.0, 8.0, 5.0), Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 1.0),