From 10902bc3f561fce18bd750fa374959feeae39d99 Mon Sep 17 00:00:00 2001 From: skorpi-and-friends <61868957+skorpi-and-friends@users.noreply.github.com> Date: Sat, 14 Aug 2021 19:45:35 +0300 Subject: [PATCH 1/3] Adds 64bit transform types and aliases ...and conversion traits. --- Cargo.toml | 3 + crates/bevy_internal/Cargo.toml | 5 + crates/bevy_math/Cargo.toml | 3 + crates/bevy_math/src/face_toward.rs | 37 +- crates/bevy_math/src/lib.rs | 4 + crates/bevy_math/src/precision.rs | 181 ++++ crates/bevy_reflect/src/impls/glam.rs | 12 +- crates/bevy_transform/Cargo.toml | 4 + .../src/components/global_transform.rs | 276 ------ crates/bevy_transform/src/components/mod.rs | 2 - .../src/components/transform.rs | 786 +++++++++++++----- 11 files changed, 807 insertions(+), 506 deletions(-) create mode 100644 crates/bevy_math/src/precision.rs delete mode 100644 crates/bevy_transform/src/components/global_transform.rs diff --git a/Cargo.toml b/Cargo.toml index f3bab82571fdd..518d221bceaff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ default = [ "vorbis", "x11", "filesystem_watcher", + # "xform_64" ] # Force dynamic linking, which improves iterative compile times @@ -88,6 +89,8 @@ subpixel_glyph_atlas = ["bevy_internal/subpixel_glyph_atlas"] # enable systems that allow for automated testing on CI bevy_ci_testing = ["bevy_internal/bevy_ci_testing"] +xform_64 = ["bevy_internal/xform_64"] + [dependencies] bevy_dylib = { path = "crates/bevy_dylib", version = "0.5.0", default-features = false, optional = true } bevy_internal = { path = "crates/bevy_internal", version = "0.5.0", default-features = false } diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 064e14b874da1..fe402e57c196a 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -47,6 +47,11 @@ webgl = ["bevy_pbr/webgl", "bevy_render/webgl"] # enable systems that allow for automated testing on CI bevy_ci_testing = ["bevy_app/bevy_ci_testing", "bevy_render/ci_limits"] +xform_64 = [ + "bevy_transform/xform_64", + "bevy_math/xform_64", +] + [dependencies] # bevy bevy_app = { path = "../bevy_app", version = "0.5.0" } diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index f3cc0b02d3db1..67bd884a6b21c 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -11,3 +11,6 @@ keywords = ["bevy"] [dependencies] glam = { version = "0.20.0", features = ["serde", "bytemuck"] } bevy_reflect = { path = "../bevy_reflect", version = "0.5.0", features = ["bevy"] } + +[features] +xform_64 = [] \ No newline at end of file diff --git a/crates/bevy_math/src/face_toward.rs b/crates/bevy_math/src/face_toward.rs index f873964b18afc..c35b5c89f34a4 100644 --- a/crates/bevy_math/src/face_toward.rs +++ b/crates/bevy_math/src/face_toward.rs @@ -1,12 +1,14 @@ -use crate::{Mat4, Vec3}; +use crate::{DMat4, DVec3, Mat4, Vec3}; /// Generates a translation / rotation matrix that faces a given target pub trait FaceToward { + type Vec3; /// Generates a translation / rotation matrix that faces a given target - fn face_toward(eye: Vec3, center: Vec3, up: Vec3) -> Self; + fn face_toward(eye: Self::Vec3, center: Self::Vec3, up: Self::Vec3) -> Self; } impl FaceToward for Mat4 { + type Vec3 = Vec3; fn face_toward(eye: Vec3, center: Vec3, up: Vec3) -> Self { let forward = (eye - center).normalize(); let right = up.cross(forward).normalize(); @@ -20,6 +22,21 @@ impl FaceToward for Mat4 { } } +impl FaceToward for DMat4 { + type Vec3 = DVec3; + fn face_toward(eye: DVec3, center: DVec3, up: DVec3) -> Self { + let forward = (eye - center).normalize(); + let right = up.cross(forward).normalize(); + let up = forward.cross(right); + DMat4::from_cols( + right.extend(0.0), + up.extend(0.0), + forward.extend(0.0), + eye.extend(1.0), + ) + } +} + #[cfg(test)] mod test { #[test] @@ -38,4 +55,20 @@ mod test { assert_eq!(matrix.z_axis, Vec4::new(0.6401844, 0.7682213, 0.0, 0.0)); assert_eq!(matrix.w_axis, Vec4::new(50.0, 60.0, 0.0, 1.0)); } + #[test] + fn face_toward_dmat4() { + use crate::{DMat4, DVec3, DVec4, FaceToward}; + + // Completely arbitrary arguments + let matrix = Mat4::face_toward( + DVec3::new(50.0, 60.0, 0.0), + DVec3::new(0.0, 0.0, 0.0), + DVec3::new(0.0, 1.0, 0.0), + ); + + assert_eq!(matrix.x_axis, DVec4::new(0.0, 0.0, -1.0, -0.0)); + assert_eq!(matrix.y_axis, DVec4::new(-0.7682213, 0.6401844, 0.0, 0.0)); + assert_eq!(matrix.z_axis, DVec4::new(0.6401844, 0.7682213, 0.0, 0.0)); + assert_eq!(matrix.w_axis, DVec4::new(50.0, 60.0, 0.0, 1.0)); + } } diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index 9a8ae797ed04b..406e270279c11 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -1,11 +1,15 @@ mod face_toward; mod geometry; +mod precision; pub use face_toward::*; pub use geometry::*; pub use glam::*; +pub use precision::*; pub mod prelude { + pub use super::precision::*; + #[doc(hidden)] pub use crate::{ BVec2, BVec3, BVec4, EulerRot, FaceToward, IVec2, IVec3, IVec4, Mat3, Mat4, Quat, Rect, diff --git a/crates/bevy_math/src/precision.rs b/crates/bevy_math/src/precision.rs new file mode 100644 index 0000000000000..776a1259a9861 --- /dev/null +++ b/crates/bevy_math/src/precision.rs @@ -0,0 +1,181 @@ +use crate::*; + +pub use defualt_tform_types::*; + +#[cfg(not(feature = "xform_64"))] +mod defualt_tform_types { + use glam::*; + + pub mod real { + pub use std::f32::*; + } + + pub type TReal = f32; + pub type TVec3 = Vec3; + pub type TQuat = Quat; + pub type TVec2 = Vec2; + pub type TMat3 = Mat3; + pub type TMat4 = Mat4; + + // TODO: mull more over this + impl super::DefaultPrecisionConvert for T + where + T: super::F32Convert + super::F64Convert, + { + type DefaultVer = F32; + + fn default_precision(&self) -> Self::DefaultVer { + self.f32() + } + } +} + +#[cfg(feature = "xform_64")] +mod defualt_tform_types { + use glam::*; + + pub mod real { + pub use std::f64::*; + } + + pub type TReal = f64; + pub type TVec3 = DVec3; + pub type TQuat = DQuat; + pub type TVec2 = DVec2; + pub type TMat3 = DMat3; + pub type TMat4 = DMat4; + + // TODO: mull more over this + impl super::DefaultPrecisionConvert for T + where + T: super::F32Convert + super::F64Convert, + { + type DefaultVer = F64; + + fn default_precision(&self) -> Self::DefaultVer { + self.f64() + } + } +} + +pub trait F32Convert { + type F32Ver; + fn f32(&self) -> Self::F32Ver; +} + +pub trait F64Convert { + type F64Ver; + fn f64(&self) -> Self::F64Ver; +} + +pub trait DefaultPrecisionConvert { + type DefaultVer; + + fn default_precision(&self) -> Self::DefaultVer; +} + +// this only works if the type implements Copy +macro_rules! impl_f32_conv_self { + ($t:ident) => { + impl F32Convert for $t { + type F32Ver = $t; + + #[inline] + fn f32(&self) -> Self::F32Ver { + *self + } + } + }; +} +impl_f32_conv_self!(f32); +impl_f32_conv_self!(Vec3); +impl_f32_conv_self!(Vec2); +impl_f32_conv_self!(Vec4); +impl_f32_conv_self!(Mat2); +impl_f32_conv_self!(Mat3); +impl_f32_conv_self!(Mat4); +impl_f32_conv_self!(Quat); +impl_f32_conv_self!(Vec3A); + +// this only works for the glam types which have `as_f32` methods. +macro_rules! impl_f32_conv_glam { + ($t:ident, $f32_t:ident) => { + impl F32Convert for $t { + type F32Ver = $f32_t; + + #[inline] + fn f32(&self) -> Self::F32Ver { + self.as_f32() + } + } + }; +} + +impl_f32_conv_glam!(DVec3, Vec3); +impl_f32_conv_glam!(DVec2, Vec2); +impl_f32_conv_glam!(DVec4, Vec4); +impl_f32_conv_glam!(DMat2, Mat2); +impl_f32_conv_glam!(DMat3, Mat3); +impl_f32_conv_glam!(DMat4, Mat4); +impl_f32_conv_glam!(DQuat, Quat); + +impl F32Convert for f64 { + type F32Ver = f32; + + fn f32(&self) -> Self::F32Ver { + *self as f32 + } +} + +// this only works if the type implements Copy +macro_rules! impl_f64_conv_self { + ($t:ident) => { + impl F64Convert for $t { + type F64Ver = $t; + + #[inline] + fn f64(&self) -> Self::F64Ver { + *self + } + } + }; +} +impl_f64_conv_self!(f64); +impl_f64_conv_self!(DVec3); +impl_f64_conv_self!(DVec2); +impl_f64_conv_self!(DVec4); +impl_f64_conv_self!(DMat2); +impl_f64_conv_self!(DMat3); +impl_f64_conv_self!(DMat4); +impl_f64_conv_self!(DQuat); + +// this only works for the glam types which have `as_f64` methods. +macro_rules! impl_f64_conv_glam { + ($t:ident, $f64_t:ident) => { + impl F64Convert for $t { + type F64Ver = $f64_t; + + #[inline] + fn f64(&self) -> Self::F64Ver { + self.as_f64() + } + } + }; +} + +impl_f64_conv_glam!(Vec3, DVec3); +impl_f64_conv_glam!(Vec2, DVec2); +impl_f64_conv_glam!(Vec4, DVec4); +impl_f64_conv_glam!(Mat2, DMat2); +impl_f64_conv_glam!(Mat3, DMat3); +impl_f64_conv_glam!(Mat4, DMat4); +impl_f64_conv_glam!(Quat, DQuat); + +impl F64Convert for f32 { + type F64Ver = f64; + + #[inline] + fn f64(&self) -> Self::F64Ver { + *self as f64 + } +} diff --git a/crates/bevy_reflect/src/impls/glam.rs b/crates/bevy_reflect/src/impls/glam.rs index de0c74c31c249..cab98294d8ed7 100644 --- a/crates/bevy_reflect/src/impls/glam.rs +++ b/crates/bevy_reflect/src/impls/glam.rs @@ -1,7 +1,10 @@ use crate as bevy_reflect; use crate::ReflectDeserialize; use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value}; -use glam::{IVec2, IVec3, IVec4, Mat3, Mat4, Quat, UVec2, UVec3, UVec4, Vec2, Vec3, Vec4}; +use glam::{ + DMat3, DMat4, DQuat, DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, Mat3, Mat4, Quat, UVec2, UVec3, + UVec4, Vec2, Vec3, Vec4, +}; impl_reflect_value!(IVec2(PartialEq, Serialize, Deserialize)); impl_reflect_value!(IVec3(PartialEq, Serialize, Deserialize)); @@ -9,6 +12,7 @@ impl_reflect_value!(IVec4(PartialEq, Serialize, Deserialize)); impl_reflect_value!(UVec2(PartialEq, Serialize, Deserialize)); impl_reflect_value!(UVec3(PartialEq, Serialize, Deserialize)); impl_reflect_value!(UVec4(PartialEq, Serialize, Deserialize)); + impl_reflect_value!(Vec2(PartialEq, Serialize, Deserialize)); impl_reflect_value!(Vec3(PartialEq, Serialize, Deserialize)); impl_reflect_value!(Vec4(PartialEq, Serialize, Deserialize)); @@ -28,3 +32,9 @@ impl_from_reflect_value!(Vec4); impl_from_reflect_value!(Mat3); impl_from_reflect_value!(Mat4); impl_from_reflect_value!(Quat); +impl_reflect_value!(DVec2(PartialEq, Serialize, Deserialize)); +impl_reflect_value!(DVec3(PartialEq, Serialize, Deserialize)); +impl_reflect_value!(DVec4(PartialEq, Serialize, Deserialize)); +impl_reflect_value!(DMat3(PartialEq, Serialize, Deserialize)); +impl_reflect_value!(DMat4(PartialEq, Serialize, Deserialize)); +impl_reflect_value!(DQuat(PartialEq, Serialize, Deserialize)); diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index 567ba74aad1bd..76c9a9e3b8eca 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -18,3 +18,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.5.0" } # other smallvec = { version = "1.6", features = ["serde", "union", "const_generics"] } + + +[features] +xform_64 = [] diff --git a/crates/bevy_transform/src/components/global_transform.rs b/crates/bevy_transform/src/components/global_transform.rs deleted file mode 100644 index bf01169353bba..0000000000000 --- a/crates/bevy_transform/src/components/global_transform.rs +++ /dev/null @@ -1,276 +0,0 @@ -use super::Transform; -use bevy_ecs::{component::Component, reflect::ReflectComponent}; -use bevy_math::{Mat3, Mat4, Quat, Vec3}; -use bevy_reflect::Reflect; -use std::ops::Mul; - -/// Describe the position of an entity relative to the reference frame. -/// -/// * To place or move an entity, you should set its [`Transform`]. -/// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. -/// * To get the global position of an entity, you should get its [`GlobalTransform`]. -/// -/// ## [`Transform`] and [`GlobalTransform`] -/// -/// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a [`Parent`](super::Parent). -/// -/// [`GlobalTransform`] is the position of an entity relative to the reference frame. -/// -/// [`GlobalTransform`] is updated from [`Transform`] in the system -/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). -/// -/// In pseudo code: -/// ```ignore -/// for entity in entities_without_parent: -/// set entity.global_transform to entity.transform -/// recursively: -/// set parent to current entity -/// for child in parent.children: -/// set child.global_transform to parent.global_transform * child.transform -/// ``` -/// -/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you -/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag -/// before the [`GlobalTransform`] is updated. -#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] -#[reflect(Component, PartialEq)] -pub struct GlobalTransform { - pub translation: Vec3, - pub rotation: Quat, - pub scale: Vec3, -} - -impl GlobalTransform { - #[doc(hidden)] - #[inline] - pub fn from_xyz(x: f32, y: f32, z: f32) -> Self { - Self::from_translation(Vec3::new(x, y, z)) - } - - /// Creates a new identity [`GlobalTransform`], with no translation, rotation, and a scale of 1 - /// on all axes. - #[inline] - pub const fn identity() -> Self { - GlobalTransform { - translation: Vec3::ZERO, - rotation: Quat::IDENTITY, - scale: Vec3::ONE, - } - } - - #[doc(hidden)] - #[inline] - pub fn from_matrix(matrix: Mat4) -> Self { - let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); - - GlobalTransform { - translation, - rotation, - scale, - } - } - - #[doc(hidden)] - #[inline] - pub fn from_translation(translation: Vec3) -> Self { - GlobalTransform { - translation, - ..Default::default() - } - } - - #[doc(hidden)] - #[inline] - pub fn from_rotation(rotation: Quat) -> Self { - GlobalTransform { - rotation, - ..Default::default() - } - } - - #[doc(hidden)] - #[inline] - pub fn from_scale(scale: Vec3) -> Self { - GlobalTransform { - scale, - ..Default::default() - } - } - - #[doc(hidden)] - #[inline] - pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self { - self.look_at(target, up); - self - } - - #[doc(hidden)] - #[inline] - pub fn with_translation(mut self, translation: Vec3) -> Self { - self.translation = translation; - self - } - - #[doc(hidden)] - #[inline] - pub fn with_rotation(mut self, rotation: Quat) -> Self { - self.rotation = rotation; - self - } - - #[doc(hidden)] - #[inline] - pub fn with_scale(mut self, scale: Vec3) -> Self { - self.scale = scale; - self - } - - /// Returns the 3d affine transformation matrix from this transforms translation, - /// rotation, and scale. - #[inline] - pub fn compute_matrix(&self) -> Mat4 { - Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) - } - - /// Get the unit vector in the local x direction - #[inline] - pub fn local_x(&self) -> Vec3 { - self.rotation * Vec3::X - } - - /// Equivalent to -local_x() - #[inline] - pub fn left(&self) -> Vec3 { - -self.local_x() - } - - /// Equivalent to local_x() - #[inline] - pub fn right(&self) -> Vec3 { - self.local_x() - } - - /// Get the unit vector in the local y direction - #[inline] - pub fn local_y(&self) -> Vec3 { - self.rotation * Vec3::Y - } - - /// Equivalent to local_y() - #[inline] - pub fn up(&self) -> Vec3 { - self.local_y() - } - - /// Equivalent to -local_y() - #[inline] - pub fn down(&self) -> Vec3 { - -self.local_y() - } - - /// Get the unit vector in the local z direction - #[inline] - pub fn local_z(&self) -> Vec3 { - self.rotation * Vec3::Z - } - - /// Equivalent to -local_z() - #[inline] - pub fn forward(&self) -> Vec3 { - -self.local_z() - } - - /// Equivalent to local_z() - #[inline] - pub fn back(&self) -> Vec3 { - self.local_z() - } - - #[doc(hidden)] - #[inline] - pub fn rotate(&mut self, rotation: Quat) { - self.rotation = rotation * self.rotation; - } - - /// Multiplies `self` with `transform` component by component, returning the - /// resulting [`GlobalTransform`] - #[inline] - pub fn mul_transform(&self, transform: Transform) -> GlobalTransform { - let translation = self.mul_vec3(transform.translation); - let rotation = self.rotation * transform.rotation; - let scale = self.scale * transform.scale; - GlobalTransform { - translation, - rotation, - scale, - } - } - - /// Returns a [`Vec3`] of this [`Transform`] applied to `value`. - #[inline] - pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 { - value = self.rotation * value; - value = self.scale * value; - value += self.translation; - value - } - - #[doc(hidden)] - #[inline] - pub fn apply_non_uniform_scale(&mut self, scale: Vec3) { - self.scale *= scale; - } - - #[doc(hidden)] - #[inline] - pub fn look_at(&mut self, target: Vec3, up: Vec3) { - let forward = Vec3::normalize(self.translation - target); - let right = up.cross(forward).normalize(); - let up = forward.cross(right); - self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward)); - } -} - -impl Default for GlobalTransform { - fn default() -> Self { - Self::identity() - } -} - -impl From for GlobalTransform { - fn from(transform: Transform) -> Self { - Self { - translation: transform.translation, - rotation: transform.rotation, - scale: transform.scale, - } - } -} - -impl Mul for GlobalTransform { - type Output = GlobalTransform; - - #[inline] - fn mul(self, global_transform: GlobalTransform) -> Self::Output { - self.mul_transform(global_transform.into()) - } -} - -impl Mul for GlobalTransform { - type Output = GlobalTransform; - - #[inline] - fn mul(self, transform: Transform) -> Self::Output { - self.mul_transform(transform) - } -} - -impl Mul for GlobalTransform { - type Output = Vec3; - - #[inline] - fn mul(self, value: Vec3) -> Self::Output { - self.mul_vec3(value) - } -} diff --git a/crates/bevy_transform/src/components/mod.rs b/crates/bevy_transform/src/components/mod.rs index 67720a2b4e08e..2429f9f36c0d0 100644 --- a/crates/bevy_transform/src/components/mod.rs +++ b/crates/bevy_transform/src/components/mod.rs @@ -1,9 +1,7 @@ mod children; -mod global_transform; mod parent; mod transform; pub use children::Children; -pub use global_transform::*; pub use parent::{Parent, PreviousParent}; pub use transform::*; diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index e97beaea20c6c..f7657445d72a5 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -1,279 +1,615 @@ -use super::GlobalTransform; -use bevy_ecs::{component::Component, reflect::ReflectComponent}; -use bevy_math::{Mat3, Mat4, Quat, Vec3}; -use bevy_reflect::Reflect; -use std::ops::Mul; - -/// Describe the position of an entity. If the entity has a parent, the position is relative -/// to its parent position. -/// -/// * To place or move an entity, you should set its [`Transform`]. -/// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. -/// * To get the global position of an entity, you should get its [`GlobalTransform`]. -/// -/// ## [`Transform`] and [`GlobalTransform`] -/// -/// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a [`Parent`](super::Parent). -/// -/// [`GlobalTransform`] is the position of an entity relative to the reference frame. -/// -/// [`GlobalTransform`] is updated from [`Transform`] in the system -/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). -/// -/// In pseudo code: -/// ```ignore -/// for entity in entities_without_parent: -/// set entity.global_transform to entity.transform -/// recursively: -/// set parent to current entity -/// for child in parent.children: -/// set child.global_transform to parent.global_transform * child.transform -/// ``` -/// -/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you -/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag -/// before the [`GlobalTransform`] is updated. -#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] -#[reflect(Component, PartialEq)] -pub struct Transform { - /// Position of the entity. In 2d, the last value of the `Vec3` is used for z-ordering. - pub translation: Vec3, - /// Rotation of the entity. - pub rotation: Quat, - /// Scale of the entity. - pub scale: Vec3, -} +macro_rules! impl_transform { + ($type_name:ident, $real:ident, $vec3:ident, $quat:ident, $mat3:ident, $mat4:ident) => { + impl $type_name { + /// Creates a new [`Transform`] at the position `(x, y, z)`. In 2d, the `z` component + /// is used for z-ordering elements: higher `z`-value will be in front of lower + /// `z`-value. + #[inline] + pub fn from_xyz(x: $real, y: $real, z: $real) -> Self { + Self::from_translation($vec3::new(x, y, z)) + } + + /// Creates a new identity [`Transform`], with no translation, rotation, and a scale of 1 on + /// all axes. + #[inline] + pub const fn identity() -> Self { + Transform { + translation: $vec3::ZERO, + rotation: $quat::IDENTITY, + scale: $vec3::ONE, + } + } + + /// Extracts the translation, rotation, and scale from `matrix`. It must be a 3d affine + /// transformation matrix. + #[inline] + pub fn from_matrix(matrix: $mat4) -> Self { + let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); + + Self { + translation, + rotation, + scale, + } + } + + /// Creates a new [`Transform`], with `translation`. Rotation will be 0 and scale 1 on + /// all axes. + #[inline] + pub fn from_translation(translation: $vec3) -> Self { + Self { + translation, + ..Default::default() + } + } + + /// Creates a new [`Transform`], with `rotation`. Translation will be 0 and scale 1 on + /// all axes. + #[inline] + pub fn from_rotation(rotation: $quat) -> Self { + Self { + rotation, + ..Default::default() + } + } + + /// Creates a new [`Transform`], with `scale`. Translation will be 0 and rotation 0 on + /// all axes. + #[inline] + pub fn from_scale(scale: $vec3) -> Self { + Self { + scale, + ..Default::default() + } + } + + /// Updates and returns this [`Transform`] by rotating it so that its unit vector in the + /// local z direction is toward `target` and its unit vector in the local y direction + /// is toward `up`. + #[inline] + pub fn looking_at(mut self, target: $vec3, up: $vec3) -> Self { + self.look_at(target, up); + self + } + + /// Returns this [`Transform`] with a new translation. + #[inline] + pub fn with_translation(mut self, translation: $vec3) -> Self { + self.translation = translation; + self + } + + /// Returns this [`Transform`] with a new rotation. + #[inline] + pub fn with_rotation(mut self, rotation: $quat) -> Self { + self.rotation = rotation; + self + } + + /// Returns this [`Transform`] with a new scale. + #[inline] + pub fn with_scale(mut self, scale: $vec3) -> Self { + self.scale = scale; + self + } + + /// Returns the 3d affine transformation matrix from this transforms translation, + /// rotation, and scale. + #[inline] + pub fn compute_matrix(&self) -> $mat4 { + $mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) + } + + /// Get the unit vector in the local x direction. + #[inline] + pub fn local_x(&self) -> $vec3 { + self.rotation * $vec3::X + } + + /// Equivalent to -local_x() + #[inline] + pub fn left(&self) -> $vec3 { + -self.local_x() + } + + /// Equivalent to local_x() + #[inline] + pub fn right(&self) -> $vec3 { + self.local_x() + } + + /// Get the unit vector in the local y direction. + #[inline] + pub fn local_y(&self) -> $vec3 { + self.rotation * $vec3::Y + } + + /// Equivalent to local_y() + #[inline] + pub fn up(&self) -> $vec3 { + self.local_y() + } + + /// Equivalent to -local_y() + #[inline] + pub fn down(&self) -> $vec3 { + -self.local_y() + } + + /// Get the unit vector in the local z direction. + #[inline] + pub fn local_z(&self) -> $vec3 { + self.rotation * $vec3::Z + } + + /// Equivalent to -local_z() + #[inline] + pub fn forward(&self) -> $vec3 { + -self.local_z() + } + + /// Equivalent to local_z() + #[inline] + pub fn back(&self) -> $vec3 { + self.local_z() + } + + /// Rotates the transform by the given rotation. + #[inline] + pub fn rotate(&mut self, rotation: $quat) { + self.rotation = rotation * self.rotation; + } + + /// Returns a [`$vec3`] of this [`Transform`] applied to `value`. + #[inline] + pub fn mul_$vec3(&self, mut value: $vec3) -> $vec3 { + value = self.rotation * value; + value = self.scale * value; + value += self.translation; + value + } + + /// Changes the `scale` of this [`Transform`], multiplying the current `scale` by + /// `scale_factor`. + #[inline] + pub fn apply_non_uniform_scale(&mut self, scale_factor: $vec3) { + self.scale *= scale_factor; + } + + /// Rotates this [`Transform`] so that its unit vector in the local z direction is toward + /// `target` and its unit vector in the local y direction is toward `up`. + #[inline] + pub fn look_at(&mut self, target: $vec3, up: $vec3) { + let forward = $vec3::normalize(self.translation - target); + let right = up.cross(forward).normalize(); + let up = forward.cross(right); + self.rotation = $quat::from_mat3(&$mat3::from_cols(right, up, forward)); + } + } -impl Transform { - /// Creates a new [`Transform`] at the position `(x, y, z)`. In 2d, the `z` component - /// is used for z-ordering elements: higher `z`-value will be in front of lower - /// `z`-value. - #[inline] - pub fn from_xyz(x: f32, y: f32, z: f32) -> Self { - Self::from_translation(Vec3::new(x, y, z)) - } + impl Default for $type_name { + fn default() -> Self { + Self::identity() + } + } - /// Creates a new identity [`Transform`], with no translation, rotation, and a scale of 1 on - /// all axes. - #[inline] - pub const fn identity() -> Self { - Transform { - translation: Vec3::ZERO, - rotation: Quat::IDENTITY, - scale: Vec3::ONE, + impl Mul<$type_name> for $type_name { + type Output = $type_name; + + #[inline] + fn mul(self, transform: $type_name) -> Self::Output { + let translation = self.mul_vec3(transform.translation); + let rotation = self.rotation * transform.rotation; + let scale = self.scale * transform.scale; + Self { + translation, + rotation, + scale, + } + } } - } - /// Extracts the translation, rotation, and scale from `matrix`. It must be a 3d affine - /// transformation matrix. - #[inline] - pub fn from_matrix(matrix: Mat4) -> Self { - let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); + impl Mul<$vec3> for $type_name { + type Output = $vec3; - Transform { - translation, - rotation, - scale, + fn mul(self, value: $vec3) -> Self::Output { + self.mul_vec3(value) + } } - } + }; +} - /// Creates a new [`Transform`], with `translation`. Rotation will be 0 and scale 1 on - /// all axes. - #[inline] - pub fn from_translation(translation: Vec3) -> Self { - Transform { - translation, - ..Default::default() - } - } +// export both versions despite feature flag +pub use xform_32::*; +pub use xform_64::*; - /// Creates a new [`Transform`], with `rotation`. Translation will be 0 and scale 1 on - /// all axes. - #[inline] - pub fn from_rotation(rotation: Quat) -> Self { - Transform { - rotation, - ..Default::default() - } +// default to one version according to feature flag +pub use defualt_tform_types::*; + +#[cfg(not(feature = "xform_64"))] +mod defualt_tform_types { + use super::xform_32::*; + + // use bevy_math::*; + + // pub type TVec3 = Vec3; + // pub type TQuat = Quat; + // pub type TVec2 = Vec2; + // pub type TMat3 = Mat3; + // pub type TMat4 = Mat4; + + pub type Transform = Transform32; + pub type GlobalTransform = GlobalTransform32; +} + +#[cfg(feature = "xform_64")] +mod defualt_tform_types { + use super::xform_64::*; + + // pub type TVec3 = DVec3; + // pub type TQuat = DQuat; + // pub type TVec2 = DVec2; + // pub type TMat3 = DMat3; + // pub type TMat4 = DMat4; + + pub type Transform = Transform64; + pub type GlobalTransform = GlobalTransform64; +} + +mod xform_32 { + use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; + use bevy_math::{F32Convert, F64Convert, Mat3, Mat4, Quat, Vec3}; + use bevy_reflect::Reflect; + use std::ops::Mul; + + /// Describe the position of an entity. If the entity has a parent, the position is relative + /// to its parent position. + /// + /// * To place or move an entity, you should set its [`Transform`]. + /// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. + /// * To get the global position of an entity, you should get its [`GlobalTransform`]. + /// + /// ## [`Transform`] and [`GlobalTransform`] + /// + /// [`Transform`] is the position of an entity relative to its parent position, or the reference + /// frame if it doesn't have a [`Parent`](super::Parent). + /// + /// [`GlobalTransform`] is the position of an entity relative to the reference frame. + /// + /// [`GlobalTransform`] is updated from [`Transform`] in the system + /// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). + /// + /// In pseudo code: + /// ```ignore + /// for entity in entities_without_parent: + /// set entity.global_transform to entity.transform + /// recursively: + /// set parent to current entity + /// for child in parent.children: + /// set child.global_transform to parent.global_transform * child.transform + /// ``` + /// + /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you + /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag + /// before the [`GlobalTransform`] is updated. + #[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] + #[reflect(Component, PartialEq)] + pub struct Transform32 { + /// Position of the entity. In 2d, the last value of the `Vec3` is used for z-ordering. + pub translation: Vec3, + /// Rotation of the entity. + pub rotation: Quat, + /// Scale of the entity. + pub scale: Vec3, } - /// Creates a new [`Transform`], with `scale`. Translation will be 0 and rotation 0 on - /// all axes. - #[inline] - pub fn from_scale(scale: Vec3) -> Self { - Transform { - scale, - ..Default::default() + impl_transform!(Transform32, f32, Vec3, Quat, Mat3, Mat4); + + impl From for Transform32 { + fn from(transform: GlobalTransform32) -> Self { + Self { + translation: transform.translation, + rotation: transform.rotation, + scale: transform.scale, + } } } - /// Updates and returns this [`Transform`] by rotating it so that its unit vector in the - /// local z direction is toward `target` and its unit vector in the local y direction - /// is toward `up`. - #[inline] - pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self { - self.look_at(target, up); - self + impl Transform32 { + /// Multiplies `self` with `transform` component by component, returning the + /// resulting [`Transform`] + #[inline] + pub fn mul_transform(&self, transform: Transform32) -> Self { + let translation = self.mul_vec3(transform.translation); + let rotation = self.rotation * transform.rotation; + let scale = self.scale * transform.scale; + Self { + translation, + rotation, + scale, + } + } } - /// Returns this [`Transform`] with a new translation. - #[inline] - pub fn with_translation(mut self, translation: Vec3) -> Self { - self.translation = translation; - self - } + impl F32Convert for Transform32 { + type F32Ver = Self; - /// Returns this [`Transform`] with a new rotation. - #[inline] - pub fn with_rotation(mut self, rotation: Quat) -> Self { - self.rotation = rotation; - self + fn f32(&self) -> Self::F32Ver { + *self + } } - - /// Returns this [`Transform`] with a new scale. - #[inline] - pub fn with_scale(mut self, scale: Vec3) -> Self { - self.scale = scale; - self + impl F64Convert for Transform32 { + type F64Ver = super::Transform64; + + fn f64(&self) -> Self::F64Ver { + super::Transform64 { + translation: self.translation.f64(), + rotation: self.rotation.f64(), + scale: self.scale.f64(), + } + } } - /// Returns the 3d affine transformation matrix from this transforms translation, - /// rotation, and scale. - #[inline] - pub fn compute_matrix(&self) -> Mat4 { - Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) + /// Describe the position of an entity relative to the reference frame. + /// + /// * To place or move an entity, you should set its [`Transform`]. + /// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. + /// * To get the global position of an entity, you should get its [`GlobalTransform`]. + /// + /// ## [`Transform`] and [`GlobalTransform`] + /// + /// [`Transform`] is the position of an entity relative to its parent position, or the reference + /// frame if it doesn't have a [`Parent`](super::Parent). + /// + /// [`GlobalTransform`] is the position of an entity relative to the reference frame. + /// + /// [`GlobalTransform`] is updated from [`Transform`] in the system + /// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). + /// + /// In pseudo code: + /// ```ignore + /// for entity in entities_without_parent: + /// set entity.global_transform to entity.transform + /// recursively: + /// set parent to current entity + /// for child in parent.children: + /// set child.global_transform to parent.global_transform * child.transform + /// ``` + /// + /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you + /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag + /// before the [`GlobalTransform`] is updated. + #[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] + #[reflect(Component, PartialEq)] + pub struct GlobalTransform32 { + pub translation: Vec3, + pub rotation: Quat, + pub scale: Vec3, } - /// Get the unit vector in the local x direction. - #[inline] - pub fn local_x(&self) -> Vec3 { - self.rotation * Vec3::X + impl_transform!(GlobalTransform32, f32, Vec3, Quat, Mat3, Mat4); + + impl GlobalTransform32 { + /// Multiplies `self` with `transform` component by component, returning the + /// resulting [`GlobalTransform`] + #[inline] + pub fn mul_transform(&self, transform: Transform32) -> GlobalTransform32 { + let translation = self.mul_vec3(transform.translation); + let rotation = self.rotation * transform.rotation; + let scale = self.scale * transform.scale; + GlobalTransform32 { + translation, + rotation, + scale, + } + } } - /// Equivalent to -local_x() - #[inline] - pub fn left(&self) -> Vec3 { - -self.local_x() + impl From for GlobalTransform32 { + fn from(transform: Transform32) -> Self { + Self { + translation: transform.translation, + rotation: transform.rotation, + scale: transform.scale, + } + } } - /// Equivalent to local_x() - #[inline] - pub fn right(&self) -> Vec3 { - self.local_x() - } + impl Mul for GlobalTransform32 { + type Output = GlobalTransform32; - /// Get the unit vector in the local y direction. - #[inline] - pub fn local_y(&self) -> Vec3 { - self.rotation * Vec3::Y + #[inline] + fn mul(self, transform: Transform32) -> Self::Output { + self.mul_transform(transform) + } } - /// Equivalent to local_y() - #[inline] - pub fn up(&self) -> Vec3 { - self.local_y() - } + impl F32Convert for GlobalTransform32 { + type F32Ver = Self; - /// Equivalent to -local_y() - #[inline] - pub fn down(&self) -> Vec3 { - -self.local_y() + fn f32(&self) -> Self::F32Ver { + *self + } } - - /// Get the unit vector in the local z direction. - #[inline] - pub fn local_z(&self) -> Vec3 { - self.rotation * Vec3::Z + impl F64Convert for GlobalTransform32 { + type F64Ver = super::GlobalTransform64; + + fn f64(&self) -> Self::F64Ver { + super::GlobalTransform64 { + translation: self.translation.f64(), + rotation: self.rotation.f64(), + scale: self.scale.f64(), + } + } } +} - /// Equivalent to -local_z() - #[inline] - pub fn forward(&self) -> Vec3 { - -self.local_z() +mod xform_64 { + use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; + use bevy_math::{DMat3, DMat4, DQuat, DVec3, F32Convert, F64Convert}; + use bevy_reflect::Reflect; + use std::ops::Mul; + + /// Describe the position of an entity. If the entity has a parent, the position is relative + /// to its parent position. + /// + /// * To place or move an entity, you should set its [`Transform`]. + /// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. + /// * To get the global position of an entity, you should get its [`GlobalTransform`]. + /// + /// ## [`Transform`] and [`GlobalTransform`] + /// + /// [`Transform`] is the position of an entity relative to its parent position, or the reference + /// frame if it doesn't have a [`Parent`](super::Parent). + /// + /// [`GlobalTransform`] is the position of an entity relative to the reference frame. + /// + /// [`GlobalTransform`] is updated from [`Transform`] in the system + /// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). + /// + /// In pseudo code: + /// ```ignore + /// for entity in entities_without_parent: + /// set entity.global_transform to entity.transform + /// recursively: + /// set parent to current entity + /// for child in parent.children: + /// set child.global_transform to parent.global_transform * child.transform + /// ``` + /// + /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you + /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag + /// before the [`GlobalTransform`] is updated. + #[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] + #[reflect(Component, PartialEq)] + pub struct Transform64 { + /// Position of the entity. In 2d, the last value of the `Vec3` is used for z-ordering. + pub translation: DVec3, + /// Rotation of the entity. + pub rotation: DQuat, + /// Scale of the entity. + pub scale: DVec3, } - /// Equivalent to local_z() - #[inline] - pub fn back(&self) -> Vec3 { - self.local_z() - } + impl_transform!(Transform64, f64, DVec3, DQuat, DMat3, DMat4); - /// Rotates the transform by the given rotation. - #[inline] - pub fn rotate(&mut self, rotation: Quat) { - self.rotation = rotation * self.rotation; + impl From for Transform64 { + fn from(transform: GlobalTransform64) -> Self { + Self { + translation: transform.translation, + rotation: transform.rotation, + scale: transform.scale, + } + } } - /// Multiplies `self` with `transform` component by component, returning the - /// resulting [`Transform`] - #[inline] - pub fn mul_transform(&self, transform: Transform) -> Self { - let translation = self.mul_vec3(transform.translation); - let rotation = self.rotation * transform.rotation; - let scale = self.scale * transform.scale; - Transform { - translation, - rotation, - scale, + impl Transform64 { + /// Multiplies `self` with `transform` component by component, returning the + /// resulting [`Transform`] + #[inline] + pub fn mul_transform(&self, transform: Transform64) -> Self { + let translation = self.mul_vec3(transform.translation); + let rotation = self.rotation * transform.rotation; + let scale = self.scale * transform.scale; + Self { + translation, + rotation, + scale, + } } } - /// Returns a [`Vec3`] of this [`Transform`] applied to `value`. - #[inline] - pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 { - value = self.rotation * value; - value = self.scale * value; - value += self.translation; - value + /// Describe the position of an entity relative to the reference frame. + /// + /// * To place or move an entity, you should set its [`Transform`]. + /// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. + /// * To get the global position of an entity, you should get its [`GlobalTransform`]. + /// + /// ## [`Transform`] and [`GlobalTransform`] + /// + /// [`Transform`] is the position of an entity relative to its parent position, or the reference + /// frame if it doesn't have a [`Parent`](super::Parent). + /// + /// [`GlobalTransform`] is the position of an entity relative to the reference frame. + /// + /// [`GlobalTransform`] is updated from [`Transform`] in the system + /// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). + /// + /// In pseudo code: + /// ```ignore + /// for entity in entities_without_parent: + /// set entity.global_transform to entity.transform + /// recursively: + /// set parent to current entity + /// for child in parent.children: + /// set child.global_transform to parent.global_transform * child.transform + /// ``` + /// + /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you + /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag + /// before the [`GlobalTransform`] is updated. + #[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] + #[reflect(Component, PartialEq)] + pub struct GlobalTransform64 { + pub translation: DVec3, + pub rotation: DQuat, + pub scale: DVec3, } - /// Changes the `scale` of this [`Transform`], multiplying the current `scale` by - /// `scale_factor`. - #[inline] - pub fn apply_non_uniform_scale(&mut self, scale_factor: Vec3) { - self.scale *= scale_factor; + impl_transform!(GlobalTransform64, f64, DVec3, DQuat, DMat3, DMat4); + + impl GlobalTransform64 { + /// Multiplies `self` with `transform` component by component, returning the + /// resulting [`GlobalTransform`] + #[inline] + pub fn mul_transform(&self, transform: Transform64) -> GlobalTransform64 { + let translation = self.mul_vec3(transform.translation); + let rotation = self.rotation * transform.rotation; + let scale = self.scale * transform.scale; + GlobalTransform64 { + translation, + rotation, + scale, + } + } } - /// Rotates this [`Transform`] so that its unit vector in the local z direction is toward - /// `target` and its unit vector in the local y direction is toward `up`. - #[inline] - pub fn look_at(&mut self, target: Vec3, up: Vec3) { - let forward = Vec3::normalize(self.translation - target); - let right = up.cross(forward).normalize(); - let up = forward.cross(right); - self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward)); + impl From for GlobalTransform64 { + fn from(transform: Transform64) -> Self { + Self { + translation: transform.translation, + rotation: transform.rotation, + scale: transform.scale, + } + } } -} -impl Default for Transform { - fn default() -> Self { - Self::identity() - } -} + impl Mul for GlobalTransform64 { + type Output = GlobalTransform64; -impl From for Transform { - fn from(transform: GlobalTransform) -> Self { - Self { - translation: transform.translation, - rotation: transform.rotation, - scale: transform.scale, + #[inline] + fn mul(self, transform: Transform64) -> Self::Output { + self.mul_transform(transform) } } -} -impl Mul for Transform { - type Output = Transform; + impl F64Convert for GlobalTransform64 { + type F64Ver = Self; - fn mul(self, transform: Transform) -> Self::Output { - self.mul_transform(transform) + #[inline] + fn f64(&self) -> Self::F64Ver { + *self + } } -} - -impl Mul for Transform { - type Output = Vec3; - - fn mul(self, value: Vec3) -> Self::Output { - self.mul_vec3(value) + impl F32Convert for GlobalTransform64 { + type F32Ver = super::GlobalTransform32; + + fn f32(&self) -> Self::F32Ver { + super::GlobalTransform32 { + translation: self.translation.f32(), + rotation: self.rotation.f32(), + scale: self.scale.f32(), + } + } } } From 1d4f334658e2cdd6630820de7b72ce0316b378b7 Mon Sep 17 00:00:00 2001 From: skorpi-and-friends <61868957+skorpi-and-friends@users.noreply.github.com> Date: Sat, 14 Aug 2021 19:46:33 +0300 Subject: [PATCH 2/3] Fixes source code to achieve compilation on both precision settings; General appraoch take was: - use chosen precision (as per flag) for cpu code - stick to 32bits for gpu code Also: - renames feature flag to "xform_64" to reduce typing for anyone `cargo check` ing both in the repo. --- Cargo.toml | 2 +- crates/bevy_gltf/src/loader.rs | 20 +-- crates/bevy_math/src/precision.rs | 121 ++++++++++++++++-- crates/bevy_pbr/src/light.rs | 20 +-- crates/bevy_pbr/src/render/light.rs | 15 ++- crates/bevy_pbr/src/render/mesh.rs | 6 +- crates/bevy_render/src/camera/bundle.rs | 7 +- crates/bevy_render/src/camera/camera.rs | 13 +- crates/bevy_render/src/camera/mod.rs | 3 +- crates/bevy_render/src/primitives/mod.rs | 2 + crates/bevy_render/src/view/mod.rs | 12 +- crates/bevy_render/src/view/visibility/mod.rs | 5 +- crates/bevy_sprite/src/render/mod.rs | 6 +- crates/bevy_text/src/text2d.rs | 4 +- .../src/components/transform.rs | 4 +- crates/bevy_ui/src/entity.rs | 4 +- crates/bevy_ui/src/flex/mod.rs | 10 +- crates/bevy_ui/src/focus.rs | 3 +- crates/bevy_ui/src/render/mod.rs | 5 +- crates/bevy_ui/src/update.rs | 5 +- examples/3d/load_gltf.rs | 9 +- examples/3d/pbr.rs | 8 +- examples/ios/src/lib.rs | 10 +- examples/tools/bevymark.rs | 32 ++--- 24 files changed, 230 insertions(+), 96 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 518d221bceaff..26bb6e0e6e136 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ default = [ "vorbis", "x11", "filesystem_watcher", - # "xform_64" + "xform_64" ] # Force dynamic linking, which improves iterative compile times diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index d7404b4088461..91269424bbe11 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -5,7 +5,7 @@ use bevy_asset::{ use bevy_core::Name; use bevy_ecs::world::World; use bevy_log::warn; -use bevy_math::{Mat4, Vec3}; +use bevy_math::{DefaultPrecisionConvert, Mat4}; use bevy_pbr::{AlphaMode, PbrBundle, StandardMaterial}; use bevy_render::{ camera::{ @@ -208,17 +208,17 @@ async fn load_gltf<'a, 'b>( .map(|mesh| mesh.index()) .and_then(|i| meshes.get(i).cloned()), transform: match node.transform() { - gltf::scene::Transform::Matrix { matrix } => { - Transform::from_matrix(bevy_math::Mat4::from_cols_array_2d(&matrix)) - } + gltf::scene::Transform::Matrix { matrix } => Transform::from_matrix( + Mat4::from_cols_array_2d(&matrix).default_precision(), + ), gltf::scene::Transform::Decomposed { translation, rotation, scale, } => Transform { - translation: bevy_math::Vec3::from(translation), - rotation: bevy_math::Quat::from_vec4(rotation.into()), - scale: bevy_math::Vec3::from(scale), + translation: bevy_math::Vec3::from(translation).default_precision(), + rotation: bevy_math::Quat::from_vec4(rotation.into()).default_precision(), + scale: bevy_math::Vec3::from(scale).default_precision(), }, }, }, @@ -456,7 +456,7 @@ fn load_node( let transform = gltf_node.transform(); let mut gltf_error = None; let mut node = world_builder.spawn_bundle(( - Transform::from_matrix(Mat4::from_cols_array_2d(&transform.matrix())), + Transform::from_matrix(Mat4::from_cols_array_2d(&transform.matrix()).default_precision()), GlobalTransform::identity(), )); @@ -544,8 +544,8 @@ fn load_node( ..Default::default() }) .insert(Aabb::from_min_max( - Vec3::from_slice(&bounds.min), - Vec3::from_slice(&bounds.max), + bevy_math::Vec3::from_slice(&bounds.min), + bevy_math::Vec3::from_slice(&bounds.max), )); } } diff --git a/crates/bevy_math/src/precision.rs b/crates/bevy_math/src/precision.rs index 776a1259a9861..08414a6eb5fb7 100644 --- a/crates/bevy_math/src/precision.rs +++ b/crates/bevy_math/src/precision.rs @@ -111,12 +111,6 @@ macro_rules! impl_f32_conv_glam { }; } -impl_f32_conv_glam!(DVec3, Vec3); -impl_f32_conv_glam!(DVec2, Vec2); -impl_f32_conv_glam!(DVec4, Vec4); -impl_f32_conv_glam!(DMat2, Mat2); -impl_f32_conv_glam!(DMat3, Mat3); -impl_f32_conv_glam!(DMat4, Mat4); impl_f32_conv_glam!(DQuat, Quat); impl F32Convert for f64 { @@ -127,6 +121,60 @@ impl F32Convert for f64 { } } +impl F32Convert for DVec3 { + type F32Ver = Vec3; + + #[inline] + fn f32(&self) -> Self::F32Ver { + self.as_vec3() + } +} + +impl F32Convert for DVec2 { + type F32Ver = Vec2; + + #[inline] + fn f32(&self) -> Self::F32Ver { + self.as_vec2() + } +} + +impl F32Convert for DVec4 { + type F32Ver = Vec4; + + #[inline] + fn f32(&self) -> Self::F32Ver { + self.as_vec4() + } +} + +impl F32Convert for DMat2 { + type F32Ver = Mat2; + + #[inline] + fn f32(&self) -> Self::F32Ver { + self.as_mat2() + } +} + +impl F32Convert for DMat3 { + type F32Ver = Mat3; + + #[inline] + fn f32(&self) -> Self::F32Ver { + self.as_mat3() + } +} + +impl F32Convert for DMat4 { + type F32Ver = Mat4; + + #[inline] + fn f32(&self) -> Self::F32Ver { + self.as_mat4() + } +} + // this only works if the type implements Copy macro_rules! impl_f64_conv_self { ($t:ident) => { @@ -162,13 +210,6 @@ macro_rules! impl_f64_conv_glam { } }; } - -impl_f64_conv_glam!(Vec3, DVec3); -impl_f64_conv_glam!(Vec2, DVec2); -impl_f64_conv_glam!(Vec4, DVec4); -impl_f64_conv_glam!(Mat2, DMat2); -impl_f64_conv_glam!(Mat3, DMat3); -impl_f64_conv_glam!(Mat4, DMat4); impl_f64_conv_glam!(Quat, DQuat); impl F64Convert for f32 { @@ -179,3 +220,57 @@ impl F64Convert for f32 { *self as f64 } } + +impl F64Convert for Vec3 { + type F64Ver = DVec3; + + #[inline] + fn f64(&self) -> Self::F64Ver { + self.as_dvec3() + } +} + +impl F64Convert for Vec2 { + type F64Ver = DVec2; + + #[inline] + fn f64(&self) -> Self::F64Ver { + self.as_dvec2() + } +} + +impl F64Convert for Vec4 { + type F64Ver = DVec4; + + #[inline] + fn f64(&self) -> Self::F64Ver { + self.as_dvec4() + } +} + +impl F64Convert for Mat2 { + type F64Ver = DMat2; + + #[inline] + fn f64(&self) -> Self::F64Ver { + self.as_dmat2() + } +} + +impl F64Convert for Mat3 { + type F64Ver = DMat3; + + #[inline] + fn f64(&self) -> Self::F64Ver { + self.as_dmat3() + } +} + +impl F64Convert for Mat4 { + type F64Ver = DMat4; + + #[inline] + fn f64(&self) -> Self::F64Ver { + self.as_dmat4() + } +} diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index f77501bb93cfb..2fcc47517227d 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -1,14 +1,14 @@ use std::collections::HashSet; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, UVec2, UVec3, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; +use bevy_math::{F32Convert, Mat4, UVec2, UVec3, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; use bevy_render::{ camera::{Camera, CameraProjection, OrthographicProjection}, color::Color, primitives::{Aabb, CubemapFrusta, Frustum, Sphere}, view::{ComputedVisibility, RenderLayers, Visibility, VisibleEntities}, }; -use bevy_transform::components::GlobalTransform; +use bevy_transform::components::{GlobalTransform, GlobalTransform32}; use bevy_window::Windows; use crate::{ @@ -466,7 +466,7 @@ pub fn assign_lights_to_clusters( let light_count = lights.iter().count(); let mut global_lights_set = HashSet::with_capacity(light_count); for (view_entity, view_transform, camera, frustum, mut clusters) in views.iter_mut() { - let view_transform = view_transform.compute_matrix(); + let view_transform = view_transform.compute_matrix().f32(); let inverse_view_transform = view_transform.inverse(); let cluster_count = clusters.aabbs.len(); let is_orthographic = camera.projection_matrix.w_axis.w == 1.0; @@ -483,7 +483,7 @@ pub fn assign_lights_to_clusters( for (light_entity, light_transform, light) in lights.iter() { let light_sphere = Sphere { - center: light_transform.translation, + center: light_transform.translation.f32(), radius: light.range, }; @@ -601,6 +601,7 @@ pub fn update_directional_light_frusta( if !directional_light.shadows_enabled { continue; } + let transform = transform.f32(); let view_projection = directional_light.shadow_projection.get_projection_matrix() * transform.compute_matrix().inverse(); @@ -622,7 +623,7 @@ pub fn update_point_light_frusta( Mat4::perspective_infinite_reverse_rh(std::f32::consts::FRAC_PI_2, 1.0, POINT_LIGHT_NEAR_Z); let view_rotations = CUBE_MAP_FACES .iter() - .map(|CubeMapFace { target, up }| GlobalTransform::identity().looking_at(*target, *up)) + .map(|CubeMapFace { target, up }| GlobalTransform32::identity().looking_at(*target, *up)) .collect::>(); let global_lights_set = global_lights @@ -639,11 +640,12 @@ pub fn update_point_light_frusta( if !point_light.shadows_enabled || !global_lights_set.contains(&entity) { continue; } + let transform = transform.f32(); // ignore scale because we don't want to effectively scale light radius and range // by applying those as a view transform to shadow map rendering of objects // and ignore rotation because we want the shadow map projections to align with the axes - let view_translation = GlobalTransform::from_translation(transform.translation); + let view_translation = GlobalTransform32::from_translation(transform.translation); let view_backward = transform.back(); for (view_rotation, frustum) in view_rotations.iter().zip(cubemap_frusta.iter_mut()) { @@ -722,7 +724,7 @@ pub fn check_light_mesh_visibility( // If we have an aabb and transform, do frustum culling if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { - if !frustum.intersects_obb(aabb, &transform.compute_matrix()) { + if !frustum.intersects_obb(aabb, &transform.compute_matrix().f32()) { continue; } } @@ -757,7 +759,7 @@ pub fn check_light_mesh_visibility( let view_mask = maybe_view_mask.copied().unwrap_or_default(); let light_sphere = Sphere { - center: transform.translation, + center: transform.translation.f32(), radius: point_light.range, }; @@ -781,7 +783,7 @@ pub fn check_light_mesh_visibility( // If we have an aabb and transform, do frustum culling if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { - let model_to_world = transform.compute_matrix(); + let model_to_world = transform.compute_matrix().f32(); // Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light if !light_sphere.intersects_obb(aabb, &model_to_world) { continue; diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 0b7cbe8a12197..94f13f1675e95 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ prelude::*, system::{lifetimeless::*, SystemParamItem}, }; -use bevy_math::{const_vec3, Mat4, UVec3, UVec4, Vec2, Vec3, Vec4, Vec4Swizzles}; +use bevy_math::{const_vec3, F32Convert, Mat4, UVec3, UVec4, Vec2, Vec3, Vec4, Vec4Swizzles}; use bevy_render::{ camera::{Camera, CameraProjection}, color::Color, @@ -27,7 +27,7 @@ use bevy_render::{ texture::*, view::{ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities}, }; -use bevy_transform::components::GlobalTransform; +use bevy_transform::components::{GlobalTransform, GlobalTransform32}; use bevy_utils::{tracing::warn, HashMap}; use std::num::NonZeroU32; @@ -405,6 +405,8 @@ pub fn extract_lights( } for (entity, directional_light, visible_entities, transform) in directional_lights.iter_mut() { + let transform = transform.f32(); + // Calulate the directional light shadow map texel size using the largest x,y dimension of // the orthographic projection divided by the shadow map resolution // NOTE: When using various PCF kernel sizes, this will need to be adjusted, according to: @@ -584,7 +586,7 @@ pub fn prepare_lights( Mat4::perspective_infinite_reverse_rh(std::f32::consts::FRAC_PI_2, 1.0, POINT_LIGHT_NEAR_Z); let cube_face_rotations = CUBE_MAP_FACES .iter() - .map(|CubeMapFace { target, up }| GlobalTransform::identity().looking_at(*target, *up)) + .map(|CubeMapFace { target, up }| GlobalTransform32::identity().looking_at(*target, *up)) .collect::>(); global_light_meta.gpu_point_lights.clear(); @@ -628,7 +630,7 @@ pub fn prepare_lights( * light.intensity) .xyz() .extend(1.0 / (light.range * light.range)), - position_radius: light.transform.translation.extend(light.radius), + position_radius: light.transform.translation.f32().extend(light.radius), flags: flags.bits, shadow_depth_bias: light.shadow_depth_bias, shadow_normal_bias: light.shadow_normal_bias, @@ -714,7 +716,8 @@ pub fn prepare_lights( // ignore scale because we don't want to effectively scale light radius and range // by applying those as a view transform to shadow map rendering of objects // and ignore rotation because we want the shadow map projections to align with the axes - let view_translation = GlobalTransform::from_translation(light.transform.translation); + let view_translation = + GlobalTransform32::from_translation(light.transform.translation.f32()); for (face_index, view_rotation) in cube_face_rotations.iter().enumerate() { let depth_texture_view = @@ -830,7 +833,7 @@ pub fn prepare_lights( ExtractedView { width: directional_light_shadow_map.size as u32, height: directional_light_shadow_map.size as u32, - transform: GlobalTransform::from_matrix(view.inverse()), + transform: GlobalTransform32::from_matrix(view.inverse()), projection, near: light.near, far: light.far, diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index fdd3b9c585296..bb7b16190a5e7 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ prelude::*, system::{lifetimeless::*, SystemParamItem}, }; -use bevy_math::Mat4; +use bevy_math::{F32Convert, Mat4}; use bevy_reflect::TypeUuid; use bevy_render::{ mesh::{GpuBufferInfo, Mesh}, @@ -108,7 +108,7 @@ pub fn extract_meshes( if !computed_visibility.is_visible { continue; } - let transform = transform.compute_matrix(); + let transform = transform.compute_matrix().f32(); caster_values.push(( entity, ( @@ -133,7 +133,7 @@ pub fn extract_meshes( if !computed_visibility.is_visible { continue; } - let transform = transform.compute_matrix(); + let transform = transform.compute_matrix().f32(); not_caster_values.push(( entity, ( diff --git a/crates/bevy_render/src/camera/bundle.rs b/crates/bevy_render/src/camera/bundle.rs index 8f61527345954..d95b2c6d3752b 100644 --- a/crates/bevy_render/src/camera/bundle.rs +++ b/crates/bevy_render/src/camera/bundle.rs @@ -7,8 +7,8 @@ use crate::{ view::VisibleEntities, }; use bevy_ecs::bundle::Bundle; -use bevy_math::Vec3; -use bevy_transform::components::{GlobalTransform, Transform}; +use bevy_math::{DefaultPrecisionConvert, Vec3}; +use bevy_transform::components::{GlobalTransform, Transform, Transform32}; use super::CameraProjection; @@ -84,7 +84,7 @@ impl OrthographicCameraBundle { depth_calculation: DepthCalculation::ZDifference, ..Default::default() }; - let transform = Transform::from_xyz(0.0, 0.0, far - 0.1); + let transform = Transform32::from_xyz(0.0, 0.0, far - 0.1); let view_projection = orthographic_projection.get_projection_matrix() * transform.compute_matrix().inverse(); let frustum = Frustum::from_view_projection( @@ -93,6 +93,7 @@ impl OrthographicCameraBundle { &transform.back(), orthographic_projection.far(), ); + let transform = transform.default_precision(); OrthographicCameraBundle { camera: Camera { name: Some(CameraPlugin::CAMERA_2D.to_string()), diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 4f73ebaf90230..93bf1e4ead636 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ reflect::ReflectComponent, system::{QuerySet, Res}, }; -use bevy_math::{Mat4, Vec2, Vec3}; +use bevy_math::{F32Convert, Mat4, TVec3, Vec2, Vec3}; use bevy_reflect::{Reflect, ReflectDeserialize}; use bevy_transform::components::GlobalTransform; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; @@ -48,13 +48,20 @@ impl Camera { &self, windows: &Windows, camera_transform: &GlobalTransform, - world_position: Vec3, + world_position: TVec3, ) -> Option { let window = windows.get(self.window)?; let window_size = Vec2::new(window.width(), window.height()); + + // TODO: camera centered RenderWorld fix + // this assumes all object xforms are relative to the camera when they arrive at the gpu + // let world_position = (world_position - camera_transform.translation).f32(); + + let world_position = world_position.f32(); + // Build a transform to convert from world to NDC using camera data let world_to_ndc: Mat4 = - self.projection_matrix * camera_transform.compute_matrix().inverse(); + self.projection_matrix * camera_transform.compute_matrix().inverse().f32(); let ndc_space_coords: Vec3 = world_to_ndc.project_point3(world_position); // NDC z-values outside of 0 < z < 1 are outside the camera frustum and are thus not in screen space if ndc_space_coords.z < 0.0 || ndc_space_coords.z > 1.0 { diff --git a/crates/bevy_render/src/camera/mod.rs b/crates/bevy_render/src/camera/mod.rs index 20baece4580e5..ed3f8751c09ee 100644 --- a/crates/bevy_render/src/camera/mod.rs +++ b/crates/bevy_render/src/camera/mod.rs @@ -5,6 +5,7 @@ mod camera; mod projection; pub use active_cameras::*; +use bevy_math::F32Convert; use bevy_transform::components::GlobalTransform; use bevy_utils::HashMap; use bevy_window::{WindowId, Windows}; @@ -91,7 +92,7 @@ fn extract_cameras( }, ExtractedView { projection: camera.projection_matrix, - transform: *transform, + transform: transform.f32(), width: window.physical_width().max(1), height: window.physical_height().max(1), near: camera.near, diff --git a/crates/bevy_render/src/primitives/mod.rs b/crates/bevy_render/src/primitives/mod.rs index deb38d3278670..2683bfe40d632 100644 --- a/crates/bevy_render/src/primitives/mod.rs +++ b/crates/bevy_render/src/primitives/mod.rs @@ -2,6 +2,8 @@ use bevy_ecs::{component::Component, reflect::ReflectComponent}; use bevy_math::{Mat4, Vec3, Vec3A, Vec4}; use bevy_reflect::Reflect; +// TODO: make precesion agnostic + /// An Axis-Aligned Bounding Box #[derive(Component, Clone, Debug, Default, Reflect)] #[reflect(Component)] diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index 89dbfa53aa785..8ec0bb2cf879e 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -17,8 +17,8 @@ use crate::{ }; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, Vec3}; -use bevy_transform::components::GlobalTransform; +use bevy_math::{F32Convert, Mat4, Vec3}; +use bevy_transform::components::GlobalTransform32; pub struct ViewPlugin; @@ -66,7 +66,7 @@ pub fn extract_msaa(mut commands: Commands, msaa: Res) { #[derive(Component)] pub struct ExtractedView { pub projection: Mat4, - pub transform: GlobalTransform, + pub transform: GlobalTransform32, pub width: u32, pub height: u32, pub near: f32, @@ -135,13 +135,15 @@ fn prepare_view_uniforms( view_uniforms.uniforms.clear(); for (entity, camera) in views.iter() { let projection = camera.projection; - let inverse_view = camera.transform.compute_matrix().inverse(); + // going to the gpu, convert into f32 + let camerfa_xform = camera.transform.f32(); + let inverse_view = camerfa_xform.compute_matrix().inverse(); let view_uniforms = ViewUniformOffset { offset: view_uniforms.uniforms.push(ViewUniform { view_proj: projection * inverse_view, inverse_view, projection, - world_position: camera.transform.translation, + world_position: camerfa_xform.translation, near: camera.near, far: camera.far, width: camera.width as f32, diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index d38e45231b337..313a97c5ac9e2 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -1,5 +1,6 @@ mod render_layers; +use bevy_math::F32Convert; pub use render_layers::*; use bevy_app::{CoreStage, Plugin}; @@ -121,6 +122,8 @@ pub fn update_frusta( mut views: Query<(&GlobalTransform, &T, &mut Frustum)>, ) { for (transform, projection, mut frustum) in views.iter_mut() { + // TODO: consider making firsta precision agnostic + let transform = transform.f32(); let view_projection = projection.get_projection_matrix() * transform.compute_matrix().inverse(); *frustum = Frustum::from_view_projection( @@ -175,7 +178,7 @@ pub fn check_visibility( // If we have an aabb and transform, do frustum culling if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { - if !frustum.intersects_obb(aabb, &transform.compute_matrix()) { + if !frustum.intersects_obb(aabb, &transform.compute_matrix().f32()) { continue; } } diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 3e5477f4b9f11..a9dbb161a6881 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -11,7 +11,7 @@ use bevy_ecs::{ prelude::*, system::{lifetimeless::*, SystemState}, }; -use bevy_math::{const_vec3, Mat4, Vec2, Vec3, Vec4Swizzles}; +use bevy_math::{const_vec3, F32Convert, Mat4, Vec2, Vec3, Vec4Swizzles}; use bevy_render::{ color::Color, render_asset::RenderAssets, @@ -222,6 +222,8 @@ pub fn extract_sprites( if !computed_visibility.is_visible { continue; } + let transform = transform.f32(); + if let Some(image) = images.get(handle) { let size = image.texture_descriptor.size; @@ -245,6 +247,8 @@ pub fn extract_sprites( if !computed_visibility.is_visible { continue; } + let transform = transform.f32(); + if let Some(texture_atlas) = texture_atlases.get(texture_atlas_handle) { if images.contains(&texture_atlas.texture) { let rect = texture_atlas.textures[atlas_sprite.index as usize]; diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index d4a59cd6c0ea5..68326bb92d447 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -5,7 +5,7 @@ use bevy_ecs::{ query::{Changed, QueryState, With}, system::{Local, Query, QuerySet, Res, ResMut}, }; -use bevy_math::{Mat4, Size, Vec3}; +use bevy_math::{F32Convert, Mat4, Size, Vec3}; use bevy_render::{texture::Image, RenderWorld}; use bevy_sprite::{ExtractedSprite, ExtractedSprites, TextureAtlas}; use bevy_transform::prelude::{GlobalTransform, Transform}; @@ -54,6 +54,8 @@ pub fn extract_text2d_sprite( }; for (entity, text, transform, calculated_size) in text2d_query.iter() { + // TODO: ui elts don't need the extra precision, consider defaulting the bundle Transform32 + let transform = transform.f32(); let (width, height) = (calculated_size.size.width, calculated_size.size.height); if let Some(text_layout) = text_pipeline.get_glyphs(&entity) { diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index f7657445d72a5..641cf491d4920 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -13,7 +13,7 @@ macro_rules! impl_transform { /// all axes. #[inline] pub const fn identity() -> Self { - Transform { + Self { translation: $vec3::ZERO, rotation: $quat::IDENTITY, scale: $vec3::ONE, @@ -162,7 +162,7 @@ macro_rules! impl_transform { /// Returns a [`$vec3`] of this [`Transform`] applied to `value`. #[inline] - pub fn mul_$vec3(&self, mut value: $vec3) -> $vec3 { + pub fn mul_vec3(&self, mut value: $vec3) -> $vec3 { value = self.rotation * value; value = self.scale * value; value += self.translation; diff --git a/crates/bevy_ui/src/entity.rs b/crates/bevy_ui/src/entity.rs index a65d5945069e4..9f12674dd07a9 100644 --- a/crates/bevy_ui/src/entity.rs +++ b/crates/bevy_ui/src/entity.rs @@ -3,11 +3,13 @@ use crate::{ CalculatedSize, FocusPolicy, Interaction, Node, Style, UiColor, UiImage, CAMERA_UI, }; use bevy_ecs::bundle::Bundle; +use bevy_math::DefaultPrecisionConvert; use bevy_render::{ camera::{Camera, DepthCalculation, OrthographicProjection, WindowOrigin}, view::{Visibility, VisibleEntities}, }; use bevy_text::Text; +// TODO: consider fixing UI elts to 32 transforms use bevy_transform::prelude::{GlobalTransform, Transform}; #[derive(Bundle, Clone, Debug, Default)] @@ -118,7 +120,7 @@ impl Default for UiCameraBundle { depth_calculation: DepthCalculation::ZDifference, ..Default::default() }, - transform: Transform::from_xyz(0.0, 0.0, far - 0.1), + transform: Transform::from_xyz(0.0, 0.0, (far - 0.1).default_precision()), global_transform: Default::default(), visible_entities: Default::default(), } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index 0bb7a573d302a..00bc57a7a8eb3 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -8,7 +8,8 @@ use bevy_ecs::{ system::{Query, Res, ResMut}, }; use bevy_log::warn; -use bevy_math::Vec2; +// TODO: ui won't most likely need f64 precision but deliberate still +use bevy_math::{DefaultPrecisionConvert, F32Convert, Vec2}; use bevy_transform::prelude::{Children, Parent, Transform}; use bevy_utils::HashMap; use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows}; @@ -271,14 +272,15 @@ pub fn flex_node_system( let physical_to_logical_factor = 1. / logical_to_physical_factor; - let to_logical = |v| (physical_to_logical_factor * v as f64) as f32; + // let to_logical = |v| (physical_to_logical_factor * v as f64) as f32; + let to_logical = |v| (physical_to_logical_factor * v as f64).default_precision(); // PERF: try doing this incrementally for (entity, mut node, mut transform, parent) in node_transform_query.iter_mut() { let layout = flex_surface.get_layout(entity).unwrap(); node.size = Vec2::new( - to_logical(layout.size.width), - to_logical(layout.size.height), + to_logical(layout.size.width).f32(), + to_logical(layout.size.height).f32(), ); let position = &mut transform.translation; position.x = to_logical(layout.location.x + layout.size.width / 2.0); diff --git a/crates/bevy_ui/src/focus.rs b/crates/bevy_ui/src/focus.rs index 14340f5ed144d..7d136ed8d0847 100644 --- a/crates/bevy_ui/src/focus.rs +++ b/crates/bevy_ui/src/focus.rs @@ -7,6 +7,7 @@ use bevy_ecs::{ system::{Local, Query, Res}, }; use bevy_input::{mouse::MouseButton, touch::Touches, Input}; +use bevy_math::F32Convert; use bevy_reflect::{Reflect, ReflectDeserialize}; use bevy_transform::components::GlobalTransform; use bevy_window::Windows; @@ -95,7 +96,7 @@ pub fn ui_focus_system( .iter_mut() .filter_map( |(entity, node, global_transform, interaction, focus_policy)| { - let position = global_transform.translation; + let position = global_transform.translation.f32(); let ui_position = position.truncate(); let extents = node.size / 2.0; let min = ui_position - extents; diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index e063cd4504142..d33551c8a47d6 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -12,7 +12,7 @@ use bevy_app::prelude::*; use bevy_asset::{AssetEvent, Assets, Handle, HandleUntyped}; use bevy_core::FloatOrd; use bevy_ecs::prelude::*; -use bevy_math::{const_vec3, Mat4, Vec2, Vec3, Vec4Swizzles}; +use bevy_math::{const_vec3, F32Convert, Mat4, Vec2, Vec3, Vec4Swizzles}; use bevy_reflect::TypeUuid; use bevy_render::{ camera::ActiveCameras, @@ -146,6 +146,8 @@ pub fn extract_uinodes( let mut extracted_uinodes = render_world.get_resource_mut::().unwrap(); extracted_uinodes.uinodes.clear(); for (uinode, transform, color, image, visibility, clip) in uinode_query.iter() { + // TODO: ui elts don't need the extra precision, consider defaulting the bundle Transform32 + let transform = transform.f32(); if !visibility.is_visible { continue; } @@ -198,6 +200,7 @@ pub fn extract_text_uinodes( if uinode.size == Vec2::ZERO { continue; } + let transform = transform.f32(); if let Some(text_layout) = text_pipeline.get_glyphs(&entity) { let text_glyphs = &text_layout.glyphs; let alignment_offset = (uinode.size / -2.0).extend(0.0); diff --git a/crates/bevy_ui/src/update.rs b/crates/bevy_ui/src/update.rs index 71dfc1950355b..a29ff19de1c6c 100644 --- a/crates/bevy_ui/src/update.rs +++ b/crates/bevy_ui/src/update.rs @@ -7,6 +7,7 @@ use bevy_ecs::{ system::{Commands, Query}, }; use bevy_math::Vec2; +use bevy_math::{DefaultPrecisionConvert, F32Convert}; use bevy_sprite::Rect; use bevy_transform::{ components::GlobalTransform, @@ -41,7 +42,7 @@ fn update_hierarchy( ) -> f32 { current_global_z += UI_Z_STEP; if let Ok(mut transform) = node_query.get_mut(entity) { - transform.translation.z = current_global_z - parent_global_z; + transform.translation.z = (current_global_z - parent_global_z).default_precision(); } if let Ok(children) = children_query.get(entity) { let current_parent_global_z = current_global_z; @@ -101,7 +102,7 @@ fn update_clipping( let children_clip = match style.overflow { Overflow::Visible => clip, Overflow::Hidden => { - let node_center = global_transform.translation.truncate(); + let node_center = global_transform.translation.f32().truncate(); let node_rect = Rect { min: node_center - node.size / 2., max: node_center + node.size / 2., diff --git a/examples/3d/load_gltf.rs b/examples/3d/load_gltf.rs index 27d02a2eedc1e..972ac2b6c6b8b 100644 --- a/examples/3d/load_gltf.rs +++ b/examples/3d/load_gltf.rs @@ -15,7 +15,8 @@ fn main() { fn setup(mut commands: Commands, asset_server: Res) { commands.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0")); commands.spawn_bundle(PerspectiveCameraBundle { - transform: Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y), + transform: Transform::from_xyz(0.7, 0.7, 1.0) + .looking_at(TVec3::new(0.0, 0.3, 0.0), TVec3::Y), ..Default::default() }); const HALF_SIZE: f32 = 1.0; @@ -42,11 +43,11 @@ fn animate_light_direction( mut query: Query<&mut Transform, With>, ) { for mut transform in query.iter_mut() { - transform.rotation = Quat::from_euler( + transform.rotation = TQuat::from_euler( EulerRot::ZYX, 0.0, - time.seconds_since_startup() as f32 * std::f32::consts::TAU / 10.0, - -std::f32::consts::FRAC_PI_4, + time.seconds_since_startup() as TReal * bevy::math::real::consts::TAU / 10.0, + -bevy::math::real::consts::FRAC_PI_4, ); } } diff --git a/examples/3d/pbr.rs b/examples/3d/pbr.rs index bd2081fbd85cb..737824ad28656 100644 --- a/examples/3d/pbr.rs +++ b/examples/3d/pbr.rs @@ -32,7 +32,7 @@ fn setup( perceptual_roughness: x01, ..Default::default() }), - transform: Transform::from_xyz(x as f32, y as f32 + 0.5, 0.0), + transform: Transform::from_xyz(x as TReal, y as TReal + 0.5, 0.0), ..Default::default() }); } @@ -54,7 +54,7 @@ fn setup( }); // light commands.spawn_bundle(PointLightBundle { - transform: Transform::from_translation(Vec3::new(50.0, 50.0, 50.0)), + transform: Transform::from_translation(TVec3::new(50.0, 50.0, 50.0)), point_light: PointLight { intensity: 600000., range: 100., @@ -64,8 +64,8 @@ fn setup( }); // camera commands.spawn_bundle(OrthographicCameraBundle { - transform: Transform::from_translation(Vec3::new(0.0, 0.0, 8.0)) - .looking_at(Vec3::default(), Vec3::Y), + transform: Transform::from_translation(TVec3::new(0.0, 0.0, 8.0)) + .looking_at(TVec3::default(), TVec3::Y), orthographic_projection: OrthographicProjection { scale: 0.01, ..Default::default() diff --git a/examples/ios/src/lib.rs b/examples/ios/src/lib.rs index f79caa85d9625..3a67f7c25de4c 100644 --- a/examples/ios/src/lib.rs +++ b/examples/ios/src/lib.rs @@ -33,12 +33,14 @@ fn touch_camera( let mut transform = camera.single_mut(); *transform = Transform::from_xyz( transform.translation.x - + (touch.position.x - last_position.x) / window.width() * 5.0, + + ((touch.position.x - last_position.x) / window.width() * 5.0) + .default_precision(), transform.translation.y, transform.translation.z - + (touch.position.y - last_position.y) / window.height() * 5.0, + + ((touch.position.y - last_position.y) / window.height() * 5.0) + .default_precision(), ) - .looking_at(Vec3::ZERO, Vec3::Y); + .looking_at(TVec3::ZERO, TVec3::Y); } *last_position = Some(touch.position); } @@ -85,7 +87,7 @@ fn setup_scene( }); // camera commands.spawn_bundle(PerspectiveCameraBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(TVec3::ZERO, TVec3::Y), ..Default::default() }); } diff --git a/examples/tools/bevymark.rs b/examples/tools/bevymark.rs index 290fdf42594aa..e671af79c36f9 100644 --- a/examples/tools/bevymark.rs +++ b/examples/tools/bevymark.rs @@ -7,8 +7,8 @@ use rand::random; const BIRDS_PER_SECOND: u32 = 10000; const _BASE_COLOR: Color = Color::rgb(5.0, 5.0, 5.0); -const GRAVITY: f32 = -9.8 * 100.0; -const MAX_VELOCITY: f32 = 750.; +const GRAVITY: TReal = -9.8 * 100.0; +const MAX_VELOCITY: TReal = 750.; const BIRD_SCALE: f32 = 0.15; const HALF_BIRD_SIZE: f32 = 256. * BIRD_SCALE * 0.5; @@ -19,7 +19,7 @@ struct BevyCounter { #[derive(Component)] struct Bird { - velocity: Vec3, + velocity: TVec3, } fn main() { @@ -179,16 +179,16 @@ fn spawn_birds( texture: Handle, ) { let window = windows.get_primary().unwrap(); - let bird_x = (window.width() as f32 / -2.) + HALF_BIRD_SIZE; - let bird_y = (window.height() as f32 / 2.) - HALF_BIRD_SIZE; + let bird_x = (window.width() / -2.) + HALF_BIRD_SIZE; + let bird_y = (window.height() / 2.) - HALF_BIRD_SIZE; for count in 0..spawn_count { let bird_z = (counter.count + count) as f32 * 0.00001; commands .spawn_bundle(SpriteBundle { texture: texture.clone(), transform: Transform { - translation: Vec3::new(bird_x, bird_y, bird_z), - scale: Vec3::splat(BIRD_SCALE), + translation: Vec3::new(bird_x, bird_y, bird_z).default_precision(), + scale: Vec3::splat(BIRD_SCALE).default_precision(), ..Default::default() }, sprite: Sprite { @@ -198,8 +198,8 @@ fn spawn_birds( ..Default::default() }) .insert(Bird { - velocity: Vec3::new( - rand::random::() * MAX_VELOCITY - (MAX_VELOCITY * 0.5), + velocity: TVec3::new( + rand::random::() * MAX_VELOCITY - (MAX_VELOCITY * 0.5), 0., 0., ), @@ -210,9 +210,9 @@ fn spawn_birds( fn movement_system(time: Res