diff --git a/crates/bevy_gizmos/src/arcs.rs b/crates/bevy_gizmos/src/arcs.rs index c44ecd22b9d83..a3f9e6287aaa3 100644 --- a/crates/bevy_gizmos/src/arcs.rs +++ b/crates/bevy_gizmos/src/arcs.rs @@ -5,7 +5,7 @@ use crate::circles::DEFAULT_CIRCLE_SEGMENTS; use crate::prelude::Gizmos; -use bevy_math::Vec2; +use bevy_math::{Angle, Radians, Vec2}; use bevy_render::color::Color; use std::f32::consts::TAU; @@ -17,9 +17,9 @@ impl<'s> Gizmos<'s> { /// # Arguments /// - `position` sets the center of this circle. /// - `radius` controls the distance from `position` to this arc, and thus its curvature. - /// - `direction_angle` sets the clockwise angle in radians between `Vec2::Y` and + /// - `direction_angle` sets the clockwise angle between `Vec2::Y` and /// the vector from `position` to the midpoint of the arc. - /// - `arc_angle` sets the length of this arc, in radians. + /// - `arc_angle` sets the length of this arc. /// /// # Example /// ``` @@ -28,12 +28,24 @@ impl<'s> Gizmos<'s> { /// # use bevy_math::prelude::*; /// # use std::f32::consts::PI; /// fn system(mut gizmos: Gizmos) { - /// gizmos.arc_2d(Vec2::ZERO, 0., PI / 4., 1., Color::GREEN); + /// gizmos.arc_2d( + /// Vec2::ZERO, + /// Radians::ZERO, + /// Radians::FRAC_PI_4, + /// 1., + /// Color::GREEN + /// ); /// /// // Arcs have 32 line-segments by default. /// // You may want to increase this for larger arcs. /// gizmos - /// .arc_2d(Vec2::ZERO, 0., PI / 4., 5., Color::RED) + /// .arc_2d( + /// Vec2::ZERO, + /// Radians::ZERO, + /// Radians::FRAC_PI_4, + /// 5., + /// Color::RED + /// ) /// .segments(64); /// } /// # bevy_ecs::system::assert_is_system(system); @@ -42,16 +54,16 @@ impl<'s> Gizmos<'s> { pub fn arc_2d( &mut self, position: Vec2, - direction_angle: f32, - arc_angle: f32, + direction_angle: impl Into, + arc_angle: impl Into, radius: f32, color: Color, ) -> Arc2dBuilder<'_, 's> { Arc2dBuilder { gizmos: self, position, - direction_angle, - arc_angle, + direction_angle: direction_angle.into(), + arc_angle: arc_angle.into(), radius, color, segments: None, @@ -63,8 +75,8 @@ impl<'s> Gizmos<'s> { pub struct Arc2dBuilder<'a, 's> { gizmos: &'a mut Gizmos<'s>, position: Vec2, - direction_angle: f32, - arc_angle: f32, + direction_angle: Radians, + arc_angle: Radians, radius: f32, color: Color, segments: Option, @@ -84,7 +96,9 @@ impl Drop for Arc2dBuilder<'_, '_> { Some(segments) => segments, // Do a linear interpolation between 1 and `DEFAULT_CIRCLE_SEGMENTS` // using the arc angle as scalar. - None => ((self.arc_angle.abs() / TAU) * DEFAULT_CIRCLE_SEGMENTS as f32).ceil() as usize, + None => { + ((self.arc_angle.abs().0 / TAU) * DEFAULT_CIRCLE_SEGMENTS as f32).ceil() as usize + } }; let positions = arc_inner(self.direction_angle, self.arc_angle, self.radius, segments) @@ -94,8 +108,8 @@ impl Drop for Arc2dBuilder<'_, '_> { } fn arc_inner( - direction_angle: f32, - arc_angle: f32, + direction_angle: Radians, + arc_angle: Radians, radius: f32, segments: usize, ) -> impl Iterator { diff --git a/crates/bevy_math/src/angle/degrees.rs b/crates/bevy_math/src/angle/degrees.rs new file mode 100644 index 0000000000000..3a671de4cc664 --- /dev/null +++ b/crates/bevy_math/src/angle/degrees.rs @@ -0,0 +1,202 @@ +use std::{ + fmt::Debug, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign}, +}; + +use crate::{Angle, Radians}; + +/// An angle in degrees. +/// +/// # Example +/// +/// ``` +/// use std::f32::consts::PI; +/// use bevy_math::{Angle, Degrees, Radians}; +/// +/// // Create angles from radians or degrees +/// let alpha = Degrees(180.0); +/// let beta = Degrees::from_radians(PI); +/// assert_eq!(alpha, beta); +/// assert_eq!(beta, Radians(PI)); +/// +/// // Add degrees and radians together (result is always radians) +/// assert_eq!(Radians(PI) + Degrees(180.0), Radians(2.0 * PI)); +/// +/// // Get float values +/// assert_eq!(alpha.0, 180.0); +/// assert_eq!(alpha.to_radians().0, PI); +/// +/// // Use trigonometric operations +/// assert_eq!(alpha.cos(), -1.0); +/// +/// // Normalize 540 degrees to range [0, 360) to get 180 degrees +/// let gamma = 3.0 * alpha; +/// let normalized = gamma.normalized(); +/// +/// // Small threshold for floating point error +/// assert!((normalized - alpha).abs() < Degrees(0.000001)); +/// ``` +// TODO: Reflect +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +pub struct Degrees(pub f32); + +impl Degrees { + /// Creates an angle in [`Degrees`] from radians. + #[inline] + pub fn from_radians(radians: f32) -> Self { + Self(radians.to_degrees()) + } + + /// Returns the angle in [`Radians`]. + #[inline] + pub fn to_radians(self) -> Radians { + Radians::from_degrees(self.0) + } +} + +impl Angle for Degrees { + const ZERO: Self = Self(0.0); + const EIGHTH: Self = Self(45.0); + const QUARTER: Self = Self(90.0); + const HALF: Self = Self(180.0); + const FULL: Self = Self(360.0); + + #[inline] + fn new(angle: f32) -> Self { + Self(angle) + } + + #[inline] + fn value(self) -> f32 { + self.0 + } + + #[inline] + fn sin(self) -> f32 { + self.to_radians().sin() + } + + #[inline] + fn cos(self) -> f32 { + self.to_radians().cos() + } + + #[inline] + fn tan(self) -> f32 { + self.to_radians().tan() + } + + #[inline] + fn sin_cos(self) -> (f32, f32) { + self.to_radians().sin_cos() + } +} + +impl From for Degrees { + fn from(angle: Radians) -> Self { + angle.to_degrees() + } +} + +impl Add for Degrees { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Sub for Degrees { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl Mul for Degrees { + type Output = Self; + + fn mul(self, rhs: f32) -> Self::Output { + Self(self.0 * rhs) + } +} + +impl Mul for f32 { + type Output = Degrees; + + fn mul(self, rhs: Degrees) -> Self::Output { + Degrees(self * rhs.0) + } +} + +impl Div for Degrees { + type Output = f32; + + fn div(self, rhs: Self) -> Self::Output { + self.0 / rhs.0 + } +} + +impl Div for Degrees { + type Output = Self; + + fn div(self, rhs: f32) -> Self::Output { + Self(self.0 / rhs) + } +} + +impl Rem for Degrees { + type Output = f32; + + fn rem(self, rhs: Self) -> Self::Output { + self.0 % rhs.0 + } +} + +impl Rem for Degrees { + type Output = Self; + + fn rem(self, rhs: f32) -> Self::Output { + Self(self.0 % rhs) + } +} + +impl Neg for Degrees { + type Output = Self; + + fn neg(self) -> Self::Output { + Self(-self.0) + } +} + +impl AddAssign for Degrees { + fn add_assign(&mut self, rhs: Degrees) { + self.0 += rhs.0; + } +} + +impl SubAssign for Degrees { + fn sub_assign(&mut self, rhs: Degrees) { + self.0 -= rhs.0; + } +} + +impl MulAssign for Degrees { + fn mul_assign(&mut self, rhs: f32) { + self.0 *= rhs; + } +} + +impl DivAssign for Degrees { + fn div_assign(&mut self, rhs: f32) { + self.0 /= rhs; + } +} + +impl RemAssign for Degrees { + fn rem_assign(&mut self, rhs: f32) { + self.0 %= rhs; + } +} diff --git a/crates/bevy_math/src/angle/mod.rs b/crates/bevy_math/src/angle/mod.rs new file mode 100644 index 0000000000000..03a467e66897d --- /dev/null +++ b/crates/bevy_math/src/angle/mod.rs @@ -0,0 +1,222 @@ +use std::ops::{Add, AddAssign, Div, Neg, Rem, Sub, SubAssign}; + +mod degrees; +mod radians; + +pub use degrees::Degrees; +pub use radians::Radians; + +/// A trait for functionality and constants shared by the [`Degrees`] and [`Radians`] types. +pub trait Angle: + Sized + + Clone + + Copy + + Add + + Sub + + Div + + Rem + + Neg + + PartialEq + + PartialOrd + + From + + From +where + Degrees: From, + Radians: From, +{ + /// An angle of zero. + const ZERO: Self; + /// A `45` degree angle. Equivalent to `π/4` radians. + const EIGHTH: Self; + /// A `90` degree angle (right angle). Equivalent to `π/2` radians. + #[doc(alias = "RIGHT_ANGLE")] + const QUARTER: Self; + /// A `180` degree angle (straight angle). Equivalent to `π` radians. + #[doc(alias = "STRAIGHT_ANGLE")] + const HALF: Self; + /// A `360` degree angle (perigon). Equivalent to `2π` radians. + #[doc(alias("PERIGON", "FULL_ANGLE"))] + const FULL: Self; + + /// Creates a new angle. + fn new(angle: f32) -> Self; + + /// Returns the angle value contained within `self`. + fn value(self) -> f32; + + /// Returns the sine of the angle. + fn sin(self) -> f32; + + /// Returns the cosine of the angle. + fn cos(self) -> f32; + + /// Returns the tangent of the angle. + fn tan(self) -> f32; + + /// Returns the sine and cosine of the angle. + fn sin_cos(self) -> (f32, f32); + + /// Returns the absolute angle. + #[inline] + fn abs(self) -> Self { + Self::new(self.value().abs()) + } + + /// Returns the minimum of the two angles, ignoring NaN. + #[inline] + fn min(self, other: Self) -> Self { + Self::new(self.value().min(other.value())) + } + + /// Returns the maximum of the two angles, ignoring NaN. + #[inline] + fn max(self, other: Self) -> Self { + Self::new(self.value().max(other.value())) + } + + /// Normalizes the angle to be within the range of `[0, 360)` degrees or `[0, 2π)` radians. + #[inline] + fn normalized(self) -> Self { + if self < Self::FULL && self >= Self::ZERO { + self + } else { + let remainder = Self::new(self % Self::FULL); + if remainder >= Self::ZERO { + remainder + } else { + remainder + Self::FULL + } + } + } + + /// Returns the largest integer angle less than or equal to `self`. + #[inline] + fn floor(self) -> Self { + Self::new(self.value().floor()) + } + + /// Returns the smallest integer angle greater than or equal to `self`. + #[inline] + fn ceil(self) -> Self { + Self::new(self.value().ceil()) + } + + /// Returns the nearest integer to `self`. If a value is half-way + /// between two integers, round away from `0.0`. + #[inline] + fn round(self) -> Self { + Self::new(self.value().round()) + } +} + +impl PartialEq for Degrees { + fn eq(&self, other: &Radians) -> bool { + *self == other.to_degrees() + } +} + +impl PartialEq for Radians { + fn eq(&self, other: &Degrees) -> bool { + self.to_degrees() == *other + } +} + +impl PartialOrd for Degrees { + fn partial_cmp(&self, other: &Radians) -> Option { + self.partial_cmp(&other.to_degrees()) + } +} + +impl PartialOrd for Radians { + fn partial_cmp(&self, other: &Degrees) -> Option { + self.to_degrees().partial_cmp(other) + } +} + +impl Add for Degrees { + type Output = Degrees; + + fn add(self, rhs: Radians) -> Self::Output { + self + rhs.to_degrees() + } +} + +impl Add for Radians { + type Output = Radians; + + fn add(self, rhs: Degrees) -> Self::Output { + self + rhs.to_radians() + } +} + +impl Sub for Degrees { + type Output = Degrees; + + fn sub(self, rhs: Radians) -> Self::Output { + self - rhs.to_degrees() + } +} + +impl Sub for Radians { + type Output = Radians; + + fn sub(self, rhs: Degrees) -> Self::Output { + self - rhs.to_radians() + } +} + +impl Div for Degrees { + type Output = f32; + + fn div(self, rhs: Radians) -> Self::Output { + self.0 / rhs.0.to_degrees() + } +} + +impl Div for Radians { + type Output = f32; + + fn div(self, rhs: Degrees) -> Self::Output { + self.0.to_degrees() / rhs.0 + } +} + +impl Rem for Degrees { + type Output = f32; + + fn rem(self, rhs: Radians) -> Self::Output { + self.0 % rhs.0.to_degrees() + } +} + +impl Rem for Radians { + type Output = f32; + + fn rem(self, rhs: Degrees) -> Self::Output { + self.0.to_degrees() % rhs.0 + } +} + +impl AddAssign for Degrees { + fn add_assign(&mut self, rhs: Radians) { + *self += rhs.to_degrees(); + } +} + +impl AddAssign for Radians { + fn add_assign(&mut self, rhs: Degrees) { + *self += rhs.to_radians(); + } +} + +impl SubAssign for Degrees { + fn sub_assign(&mut self, rhs: Radians) { + *self -= rhs.to_degrees(); + } +} + +impl SubAssign for Radians { + fn sub_assign(&mut self, rhs: Degrees) { + *self -= rhs.to_radians(); + } +} diff --git a/crates/bevy_math/src/angle/radians.rs b/crates/bevy_math/src/angle/radians.rs new file mode 100644 index 0000000000000..1e36d27905309 --- /dev/null +++ b/crates/bevy_math/src/angle/radians.rs @@ -0,0 +1,219 @@ +use std::{ + fmt::Debug, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign}, +}; + +use crate::{Angle, Degrees}; + +/// An angle in radians. +/// +/// # Example +/// +/// ``` +/// use std::f32::consts::PI; +/// use bevy_math::{Angle, Degrees, Radians}; +/// +/// // Create angles from radians or degrees +/// let alpha = Radians(PI); +/// let beta = Radians::from_degrees(180.0); +/// assert_eq!(alpha, beta); +/// assert_eq!(beta, Degrees(180.0)); +/// +/// // Add degrees and radians together (result is always radians) +/// assert_eq!(Radians(PI) + Degrees(180.0), Radians(2.0 * PI)); +/// +/// // Get float values +/// assert_eq!(alpha.0, PI); +/// assert_eq!(alpha.to_degrees().0, 180.0); +/// +/// // Use trigonometric operations +/// assert_eq!(alpha.cos(), -1.0); +/// +/// // Normalize 3π to range [0, 2π) to get π +/// let gamma = 3.0 * alpha; +/// let normalized = gamma.normalized(); +/// +/// // Small threshold for floating point error +/// assert!((normalized - alpha).abs() < Radians(0.000001)); +/// ``` +// TODO: Reflect +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +pub struct Radians(pub f32); + +impl Radians { + /// The angle 2π. Equivalent to `Radians::FULL`. + #[doc(alias = "TWO_PI")] + pub const TAU: Self = Self(std::f32::consts::TAU); + /// The angle π (π). Equivalent to `Radians::HALF`. + pub const PI: Self = Self(std::f32::consts::PI); + /// The angle π/2. Equivalent to `Radians::QUARTER`. + #[doc(alias = "HALF_PI")] + pub const FRAC_PI_2: Self = Self(std::f32::consts::FRAC_PI_2); + /// The angle π/3. + pub const FRAC_PI_3: Self = Self(std::f32::consts::FRAC_PI_3); + /// The angle π/4. Equivalent to `Radians::EIGHTH`. + pub const FRAC_PI_4: Self = Self(std::f32::consts::FRAC_PI_4); + /// The angle π/6. + pub const FRAC_PI_6: Self = Self(std::f32::consts::FRAC_PI_6); + /// The angle π/8. + pub const FRAC_PI_8: Self = Self(std::f32::consts::FRAC_PI_8); + + /// Creates an angle in [`Radians`] from degrees. + #[inline] + pub fn from_degrees(degrees: f32) -> Self { + Self(degrees.to_radians()) + } + + /// Returns the angle in [`Degrees`]. + #[inline] + pub fn to_degrees(self) -> Degrees { + Degrees::from_radians(self.0) + } +} + +impl Angle for Radians { + const ZERO: Self = Self(0.0); + const EIGHTH: Self = Self::FRAC_PI_4; + const QUARTER: Self = Self::FRAC_PI_2; + const HALF: Self = Self::PI; + const FULL: Self = Self::TAU; + + #[inline] + fn new(angle: f32) -> Self { + Self(angle) + } + + #[inline] + fn value(self) -> f32 { + self.0 + } + + #[inline] + fn sin(self) -> f32 { + self.0.sin() + } + + #[inline] + fn cos(self) -> f32 { + self.0.cos() + } + + #[inline] + fn tan(self) -> f32 { + self.0.tan() + } + + #[inline] + fn sin_cos(self) -> (f32, f32) { + self.0.sin_cos() + } +} + +impl From for Radians { + fn from(angle: Degrees) -> Self { + angle.to_radians() + } +} + +impl Add for Radians { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Sub for Radians { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl Mul for Radians { + type Output = Self; + + fn mul(self, rhs: f32) -> Self::Output { + Self(self.0 * rhs) + } +} + +impl Mul for f32 { + type Output = Radians; + + fn mul(self, rhs: Radians) -> Self::Output { + Radians(self * rhs.0) + } +} + +impl Div for Radians { + type Output = f32; + + fn div(self, rhs: Self) -> Self::Output { + self.0 / rhs.0 + } +} + +impl Div for Radians { + type Output = Self; + + fn div(self, rhs: f32) -> Self::Output { + Self(self.0 / rhs) + } +} + +impl Rem for Radians { + type Output = f32; + + fn rem(self, rhs: Self) -> Self::Output { + self.0 % rhs.0 + } +} + +impl Rem for Radians { + type Output = Self; + + fn rem(self, rhs: f32) -> Self::Output { + Self(self.0 % rhs) + } +} + +impl Neg for Radians { + type Output = Self; + + fn neg(self) -> Self::Output { + Self(-self.0) + } +} + +impl AddAssign for Radians { + fn add_assign(&mut self, rhs: Radians) { + self.0 += rhs.0; + } +} + +impl SubAssign for Radians { + fn sub_assign(&mut self, rhs: Radians) { + self.0 -= rhs.0; + } +} + +impl MulAssign for Radians { + fn mul_assign(&mut self, rhs: f32) { + self.0 *= rhs; + } +} + +impl DivAssign for Radians { + fn div_assign(&mut self, rhs: f32) { + self.0 /= rhs; + } +} + +impl RemAssign for Radians { + fn rem_assign(&mut self, rhs: f32) { + self.0 %= rhs; + } +} diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index c6fb416d7eacf..f035abc3c02fc 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -7,6 +7,7 @@ #![warn(missing_docs)] mod affine3; +mod angle; mod aspect_ratio; pub mod cubic_splines; pub mod primitives; @@ -14,6 +15,7 @@ mod ray; mod rects; pub use affine3::*; +pub use angle::{Angle, Degrees, Radians}; pub use aspect_ratio::AspectRatio; pub use ray::{Ray2d, Ray3d}; pub use rects::*; @@ -22,6 +24,7 @@ pub use rects::*; pub mod prelude { #[doc(hidden)] pub use crate::{ + angle::{Angle, Degrees, Radians}, cubic_splines::{ CubicBSpline, CubicBezier, CubicCardinalSpline, CubicGenerator, CubicHermite, CubicSegment, diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index c67d0cfe578cd..00a36c283282f 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -2,7 +2,8 @@ use std::collections::HashSet; use bevy_ecs::prelude::*; use bevy_math::{ - AspectRatio, Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles, + Angle, AspectRatio, Mat4, Radians, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, + Vec4Swizzles, }; use bevy_reflect::prelude::*; use bevy_render::{ @@ -102,6 +103,7 @@ pub struct SpotLight { /// shadow map's texel size so that it can be small close to the camera and gets larger further /// away. pub shadow_normal_bias: f32, + // TODO: Replace these with `Radians` once it implements `Reflect` /// Angle defining the distance from the spot light direction to the outer limit /// of the light's cone of effect. /// `outer_angle` should be < `PI / 2.0`. @@ -1155,7 +1157,7 @@ pub(crate) struct PointLightAssignmentData { transform: GlobalTransform, range: f32, shadows_enabled: bool, - spot_light_angle: Option, + spot_light_angle: Option, render_layers: RenderLayers, } @@ -1254,7 +1256,7 @@ pub(crate) fn assign_lights_to_clusters( transform: *transform, shadows_enabled: spot_light.shadows_enabled, range: spot_light.range, - spot_light_angle: Some(spot_light.outer_angle), + spot_light_angle: Some(Radians(spot_light.outer_angle)), render_layers: maybe_layers.copied().unwrap_or_default(), } }, @@ -1950,7 +1952,7 @@ pub fn update_spot_light_frusta( let view_backward = transform.back(); let spot_view = spot_light_view_matrix(transform); - let spot_projection = spot_light_projection_matrix(spot_light.outer_angle); + let spot_projection = spot_light_projection_matrix(Radians(spot_light.outer_angle)); let view_projection = spot_projection * spot_view.inverse(); *frustum = Frustum::from_view_projection_custom_far( diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 9b9b635ab0f83..901688cfd6bb4 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1,6 +1,6 @@ use bevy_core_pipeline::core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT}; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, UVec3, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; +use bevy_math::{Angle, Mat4, Radians, UVec3, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; use bevy_render::{ camera::Camera, color::Color, @@ -35,7 +35,7 @@ pub struct ExtractedPointLight { shadows_enabled: bool, shadow_depth_bias: f32, shadow_normal_bias: f32, - spot_light_angles: Option<(f32, f32)>, + spot_light_angles: Option<(Radians, Radians)>, } #[derive(Component, Debug)] @@ -415,7 +415,10 @@ pub fn extract_lights( shadow_normal_bias: spot_light.shadow_normal_bias * texel_size * std::f32::consts::SQRT_2, - spot_light_angles: Some((spot_light.inner_angle, spot_light.outer_angle)), + spot_light_angles: Some(( + Radians(spot_light.inner_angle), + Radians(spot_light.outer_angle), + )), }, render_visible_entities, ), @@ -635,9 +638,9 @@ pub(crate) fn spot_light_view_matrix(transform: &GlobalTransform) -> Mat4 { ) } -pub(crate) fn spot_light_projection_matrix(angle: f32) -> Mat4 { +pub(crate) fn spot_light_projection_matrix(angle: Radians) -> Mat4 { // spot light projection FOV is 2x the angle from spot light center to outer edge - Mat4::perspective_infinite_reverse_rh(angle * 2.0, 1.0, POINT_LIGHT_NEAR_Z) + Mat4::perspective_infinite_reverse_rh(angle.0 * 2.0, 1.0, POINT_LIGHT_NEAR_Z) } #[allow(clippy::too_many_arguments)] diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 316ee97719d7e..42ff19f60eea0 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -1,5 +1,6 @@ use super::GlobalTransform; use bevy_ecs::{component::Component, reflect::ReflectComponent}; +use bevy_math::Radians; use bevy_math::{Affine3A, Mat3, Mat4, Quat, Vec3}; use bevy_reflect::prelude::*; use bevy_reflect::Reflect; @@ -251,36 +252,36 @@ impl Transform { self.rotation = rotation * self.rotation; } - /// Rotates this [`Transform`] around the given `axis` by `angle` (in radians). + /// Rotates this [`Transform`] around the given `axis` by `angle` in the counterclockwise direction. /// /// If this [`Transform`] has a parent, the `axis` is relative to the rotation of the parent. #[inline] - pub fn rotate_axis(&mut self, axis: Vec3, angle: f32) { - self.rotate(Quat::from_axis_angle(axis, angle)); + pub fn rotate_axis(&mut self, axis: Vec3, angle: impl Into) { + self.rotate(Quat::from_axis_angle(axis, angle.into().0)); } - /// Rotates this [`Transform`] around the `X` axis by `angle` (in radians). + /// Rotates this [`Transform`] around the `X` axis by `angle` in the counterclockwise direction. /// /// If this [`Transform`] has a parent, the axis is relative to the rotation of the parent. #[inline] - pub fn rotate_x(&mut self, angle: f32) { - self.rotate(Quat::from_rotation_x(angle)); + pub fn rotate_x(&mut self, angle: impl Into) { + self.rotate(Quat::from_rotation_x(angle.into().0)); } - /// Rotates this [`Transform`] around the `Y` axis by `angle` (in radians). + /// Rotates this [`Transform`] around the `Y` axis by `angle` in the counterclockwise direction. /// /// If this [`Transform`] has a parent, the axis is relative to the rotation of the parent. #[inline] - pub fn rotate_y(&mut self, angle: f32) { - self.rotate(Quat::from_rotation_y(angle)); + pub fn rotate_y(&mut self, angle: impl Into) { + self.rotate(Quat::from_rotation_y(angle.into().0)); } - /// Rotates this [`Transform`] around the `Z` axis by `angle` (in radians). + /// Rotates this [`Transform`] around the `Z` axis by `angle` in the counterclockwise direction. /// /// If this [`Transform`] has a parent, the axis is relative to the rotation of the parent. #[inline] - pub fn rotate_z(&mut self, angle: f32) { - self.rotate(Quat::from_rotation_z(angle)); + pub fn rotate_z(&mut self, angle: impl Into) { + self.rotate(Quat::from_rotation_z(angle.into().0)); } /// Rotates this [`Transform`] by the given `rotation`. @@ -291,28 +292,28 @@ impl Transform { self.rotation *= rotation; } - /// Rotates this [`Transform`] around its local `axis` by `angle` (in radians). + /// Rotates this [`Transform`] around its local `axis` by `angle` in the counterclockwise direction. #[inline] - pub fn rotate_local_axis(&mut self, axis: Vec3, angle: f32) { - self.rotate_local(Quat::from_axis_angle(axis, angle)); + pub fn rotate_local_axis(&mut self, axis: Vec3, angle: impl Into) { + self.rotate_local(Quat::from_axis_angle(axis, angle.into().0)); } - /// Rotates this [`Transform`] around its local `X` axis by `angle` (in radians). + /// Rotates this [`Transform`] around its local `X` axis by `angle` in the counterclockwise direction. #[inline] - pub fn rotate_local_x(&mut self, angle: f32) { - self.rotate_local(Quat::from_rotation_x(angle)); + pub fn rotate_local_x(&mut self, angle: impl Into) { + self.rotate_local(Quat::from_rotation_x(angle.into().0)); } - /// Rotates this [`Transform`] around its local `Y` axis by `angle` (in radians). + /// Rotates this [`Transform`] around its local `Y` axis by `angle` in the counterclockwise direction. #[inline] - pub fn rotate_local_y(&mut self, angle: f32) { - self.rotate_local(Quat::from_rotation_y(angle)); + pub fn rotate_local_y(&mut self, angle: impl Into) { + self.rotate_local(Quat::from_rotation_y(angle.into().0)); } - /// Rotates this [`Transform`] around its local `Z` axis by `angle` (in radians). + /// Rotates this [`Transform`] around its local `Z` axis by `angle` in the counterclockwise direction. #[inline] - pub fn rotate_local_z(&mut self, angle: f32) { - self.rotate_local(Quat::from_rotation_z(angle)); + pub fn rotate_local_z(&mut self, angle: impl Into) { + self.rotate_local(Quat::from_rotation_z(angle.into().0)); } /// Translates this [`Transform`] around a `point` in space. diff --git a/examples/2d/2d_gizmos.rs b/examples/2d/2d_gizmos.rs index d3dcd7c960f6a..d5eccfc487f24 100644 --- a/examples/2d/2d_gizmos.rs +++ b/examples/2d/2d_gizmos.rs @@ -52,7 +52,13 @@ fn system(mut gizmos: Gizmos, time: Res