From 9881631b546c677d5f95fb571edc207fc6078bf9 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 30 Dec 2023 00:50:41 +0200 Subject: [PATCH 01/21] Add `Angle` type and `Float` trait --- crates/bevy_gizmos/src/arcs.rs | 17 +- crates/bevy_gizmos/src/circles.rs | 4 +- crates/bevy_gltf/src/loader.rs | 6 +- crates/bevy_input/src/touch.rs | 4 +- crates/bevy_math/Cargo.toml | 1 + crates/bevy_math/src/angle.rs | 255 ++++++++++++++++++ crates/bevy_math/src/float.rs | 161 +++++++++++ crates/bevy_math/src/lib.rs | 7 +- crates/bevy_pbr/src/light.rs | 12 +- crates/bevy_pbr/src/render/light.rs | 8 +- crates/bevy_reflect/src/impls/angle.rs | 6 + crates/bevy_reflect/src/lib.rs | 1 + .../src/components/transform.rs | 49 ++-- crates/bevy_winit/src/converters.rs | 4 +- examples/2d/2d_gizmos.rs | 8 +- examples/2d/pixel_grid_snap.rs | 2 +- examples/2d/rotation.rs | 9 +- examples/3d/3d_shapes.rs | 2 +- examples/3d/deferred_rendering.rs | 8 +- examples/3d/generate_custom_mesh.rs | 6 +- examples/3d/lighting.rs | 12 +- examples/3d/parallax_mapping.rs | 10 +- examples/3d/parenting.rs | 2 +- examples/3d/render_to_texture.rs | 8 +- examples/3d/skybox.rs | 2 +- examples/3d/spotlight.rs | 7 +- examples/ecs/hierarchy.rs | 4 +- examples/games/alien_cake_addict.rs | 2 +- examples/games/contributors.rs | 4 +- examples/shader/post_processing.rs | 4 +- examples/stress_tests/many_cubes.rs | 7 +- examples/stress_tests/many_foxes.rs | 8 +- examples/stress_tests/many_gizmos.rs | 2 +- examples/stress_tests/many_lights.rs | 2 +- examples/stress_tests/many_sprites.rs | 2 +- examples/stress_tests/transform_hierarchy.rs | 7 +- examples/tools/gamepad_viewer.rs | 13 +- examples/transforms/3d_rotation.rs | 6 +- examples/window/low_power.rs | 4 +- 39 files changed, 563 insertions(+), 113 deletions(-) create mode 100644 crates/bevy_math/src/angle.rs create mode 100644 crates/bevy_math/src/float.rs create mode 100644 crates/bevy_reflect/src/impls/angle.rs diff --git a/crates/bevy_gizmos/src/arcs.rs b/crates/bevy_gizmos/src/arcs.rs index c44ecd22b9d83..bd779c17ebc3b 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, Vec2}; use bevy_render::color::Color; use std::f32::consts::TAU; @@ -42,8 +42,8 @@ impl<'s> Gizmos<'s> { pub fn arc_2d( &mut self, position: Vec2, - direction_angle: f32, - arc_angle: f32, + direction_angle: Angle, + arc_angle: Angle, radius: f32, color: Color, ) -> Arc2dBuilder<'_, 's> { @@ -63,8 +63,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: Angle, + arc_angle: Angle, radius: f32, color: Color, segments: Option, @@ -84,7 +84,8 @@ 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.as_radians().abs() / TAU) * DEFAULT_CIRCLE_SEGMENTS as f32) + .ceil() as usize, }; let positions = arc_inner(self.direction_angle, self.arc_angle, self.radius, segments) @@ -94,8 +95,8 @@ impl Drop for Arc2dBuilder<'_, '_> { } fn arc_inner( - direction_angle: f32, - arc_angle: f32, + direction_angle: Angle, + arc_angle: Angle, radius: f32, segments: usize, ) -> impl Iterator { diff --git a/crates/bevy_gizmos/src/circles.rs b/crates/bevy_gizmos/src/circles.rs index d24dec62e350e..57b43ca7bc9b8 100644 --- a/crates/bevy_gizmos/src/circles.rs +++ b/crates/bevy_gizmos/src/circles.rs @@ -4,7 +4,7 @@ //! and assorted support items. use crate::prelude::Gizmos; -use bevy_math::{Quat, Vec2, Vec3}; +use bevy_math::{Angle, Quat, Vec2, Vec3}; use bevy_render::color::Color; use std::f32::consts::TAU; @@ -12,7 +12,7 @@ pub(crate) const DEFAULT_CIRCLE_SEGMENTS: usize = 32; fn circle_inner(radius: f32, segments: usize) -> impl Iterator { (0..segments + 1).map(move |i| { - let angle = i as f32 * TAU / segments as f32; + let angle = Angle::radians(i as f32 * TAU / segments as f32); Vec2::from(angle.sin_cos()) * radius }) } diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 4d1d3e772f3a8..0ec8e134b05e2 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -7,7 +7,7 @@ use bevy_core_pipeline::prelude::Camera3dBundle; use bevy_ecs::{entity::Entity, world::World}; use bevy_hierarchy::{BuildWorldChildren, WorldChildBuilder}; use bevy_log::{error, warn}; -use bevy_math::{Mat4, Vec3}; +use bevy_math::{Angle, Mat4, Vec3}; use bevy_pbr::{ AlphaMode, DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight, PointLightBundle, SpotLight, SpotLightBundle, StandardMaterial, MAX_JOINTS, @@ -1101,8 +1101,8 @@ fn load_node( intensity: light.intensity() * std::f32::consts::PI * 4.0, range: light.range().unwrap_or(20.0), radius: light.range().unwrap_or(0.0), - inner_angle: inner_cone_angle, - outer_angle: outer_cone_angle, + inner_angle: Angle::radians(inner_cone_angle), + outer_angle: Angle::radians(outer_cone_angle), ..Default::default() }, ..Default::default() diff --git a/crates/bevy_input/src/touch.rs b/crates/bevy_input/src/touch.rs index be8235fec0253..19b2a302e02ee 100644 --- a/crates/bevy_input/src/touch.rs +++ b/crates/bevy_input/src/touch.rs @@ -2,7 +2,7 @@ use bevy_ecs::event::{Event, EventReader}; use bevy_ecs::system::{ResMut, Resource}; -use bevy_math::Vec2; +use bevy_math::{Angle, Vec2}; use bevy_reflect::Reflect; use bevy_utils::HashMap; @@ -83,7 +83,7 @@ pub enum ForceTouch { /// A value of 0 radians indicates that the stylus is parallel to the /// surface. The value of this property is Pi/2 when the stylus is /// perpendicular to the surface. - altitude_angle: Option, + altitude_angle: Option>, }, /// If the platform reports the force as normalized, we have no way of /// knowing how much pressure 1.0 corresponds to – we know it's the maximum diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index 7ee418a42158e..c3128263e2b41 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -10,6 +10,7 @@ keywords = ["bevy"] [dependencies] glam = { version = "0.24.1", features = ["bytemuck"] } +num-traits = { version = "0.2.17", default-features = false } serde = { version = "1", features = ["derive"], optional = true } [features] diff --git a/crates/bevy_math/src/angle.rs b/crates/bevy_math/src/angle.rs new file mode 100644 index 0000000000000..2bc8565c96ef3 --- /dev/null +++ b/crates/bevy_math/src/angle.rs @@ -0,0 +1,255 @@ +use std::{ + fmt::Debug, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; + +use super::{float::Float, Vec2}; +use glam::DVec2; + +/// An angle in radians. +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +pub struct Angle(T); + +impl Default for Angle { + fn default() -> Self { + Self::ZERO + } +} + +impl Angle { + /// Rotates the given vector by `self`. + #[inline] + pub fn rotate(&self, vec: Vec2) -> Vec2 { + Vec2::new( + vec.x * self.sin() + vec.y * self.cos(), + vec.x * self.cos() - vec.y * self.sin(), + ) + } +} + +impl Angle { + /// Rotates the given vector by `self`. + #[inline] + pub fn rotate(&self, vec: DVec2) -> DVec2 { + DVec2::new( + vec.x * self.sin() + vec.y * self.cos(), + vec.x * self.cos() - vec.y * self.sin(), + ) + } +} + +impl Angle { + /// An angle of zero. + pub const ZERO: Self = Self(T::ZERO); + /// The angle 2π in radians. + pub const TAU: Self = Self(T::TAU); + /// The angle π (pi) in radians. + pub const PI: Self = Self(T::PI); + /// The angle π/2 in radians. + pub const FRAC_PI_2: Self = Self(T::FRAC_PI_2); + /// The angle π/3 in radians. + pub const FRAC_PI_3: Self = Self(T::FRAC_PI_3); + /// The angle π/4 in radians. + pub const FRAC_PI_4: Self = Self(T::FRAC_PI_4); + /// The angle π/6 in radians. + pub const FRAC_PI_6: Self = Self(T::FRAC_PI_6); + /// The angle π/8 in radians. + pub const FRAC_PI_8: Self = Self(T::FRAC_PI_8); + + /// Returns the sine of the angle in radians. + #[inline] + pub fn sin(&self) -> T { + self.0.sin() + } + + /// Returns the cosine of the angle in radians. + #[inline] + pub fn cos(&self) -> T { + self.0.cos() + } + + /// Returns the tangent of the angle in radians. + #[inline] + pub fn tan(&self) -> T { + self.0.tan() + } + + /// Returns the sine and cosine of the angle in radians. + #[inline] + pub fn sin_cos(&self) -> (T, T) { + self.0.sin_cos() + } + + /// Creates an [`Angle`] from radians. + #[inline] + pub const fn radians(radians: T) -> Self { + Self(radians) + } + + /// Creates an [`Angle`] from degrees. + #[inline] + pub fn degrees(degrees: T) -> Self { + Self(degrees.to_radians()) + } + + /// Returns the angle in radians. + #[inline] + pub fn as_radians(&self) -> T { + self.0 + } + + /// Returns the angle in degrees. + #[inline] + pub fn as_degrees(&self) -> T { + self.as_radians().to_degrees() + } + + /// Returns the absolute angle. + #[inline] + pub fn abs(&self) -> Self { + Self(self.0.abs()) + } + + /// Returns the minimum of the two angles, ignoring NaN. + #[inline] + pub fn min(&self, other: Self) -> Self { + Angle::radians(self.0.min(other.0)) + } +} + +impl Add for Angle { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Sub for Angle { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl Mul for Angle { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + Self(self.0 * rhs.0) + } +} + +impl Div for Angle { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + Self(self.0 / rhs.0) + } +} + +impl Mul for Angle { + type Output = Self; + + fn mul(self, rhs: T) -> Self::Output { + Self(self.0 * rhs) + } +} + +impl Mul> for f32 { + type Output = Angle; + + fn mul(self, rhs: Angle) -> Self::Output { + Angle::radians(self * rhs.as_radians()) + } +} + +impl Mul> for f64 { + type Output = Angle; + + fn mul(self, rhs: Angle) -> Self::Output { + Angle::radians(self * rhs.as_radians()) + } +} + +impl Div for Angle { + type Output = Self; + + fn div(self, rhs: T) -> Self::Output { + Self::radians(self.as_radians() / rhs) + } +} + +impl Div> for f32 { + type Output = Angle; + + fn div(self, rhs: Angle) -> Self::Output { + Angle::radians(self / rhs.as_radians()) + } +} + +impl Div> for f64 { + type Output = Angle; + + fn div(self, rhs: Angle) -> Self::Output { + Angle::radians(self / rhs.as_radians()) + } +} + +impl Neg for Angle { + type Output = Self; + + fn neg(self) -> Self::Output { + Self(-self.0) + } +} + +impl AddAssign> for Angle { + fn add_assign(&mut self, rhs: Angle) { + self.0 += rhs.0; + } +} + +impl SubAssign> for Angle { + fn sub_assign(&mut self, rhs: Angle) { + self.0 -= rhs.0; + } +} + +impl MulAssign> for Angle { + fn mul_assign(&mut self, rhs: Angle) { + self.0 *= rhs.0; + } +} + +impl DivAssign> for Angle { + fn div_assign(&mut self, rhs: Angle) { + self.0 /= rhs.0; + } +} + +impl AddAssign for Angle { + fn add_assign(&mut self, rhs: T) { + self.0 += rhs; + } +} + +impl SubAssign for Angle { + fn sub_assign(&mut self, rhs: T) { + self.0 -= rhs; + } +} + +impl MulAssign for Angle { + fn mul_assign(&mut self, rhs: T) { + self.0 *= rhs; + } +} + +impl DivAssign for Angle { + fn div_assign(&mut self, rhs: T) { + self.0 /= rhs; + } +} diff --git a/crates/bevy_math/src/float.rs b/crates/bevy_math/src/float.rs new file mode 100644 index 0000000000000..2b44dd12484a6 --- /dev/null +++ b/crates/bevy_math/src/float.rs @@ -0,0 +1,161 @@ +//! Contains a generic trait for floating-point numbers. + +use std::{ + fmt::Debug, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; + +/// A trait for generic floats. +pub trait Float: + Sized + + Clone + + Copy + + Debug + + Default + + PartialEq + + PartialOrd + + Add + + Sub + + Mul + + Div + + AddAssign + + SubAssign + + MulAssign + + DivAssign + + Neg +{ + /// A value of 0. + const ZERO: Self; + /// A value of 1. + const ONE: Self; + /// A value of -1. + const NEG_ONE: Self; + /// 2π + const TAU: Self; + /// π (pi) + const PI: Self; + /// π/2 + const FRAC_PI_2: Self; + /// π/3 + const FRAC_PI_3: Self; + /// π/4 + const FRAC_PI_4: Self; + /// π/6 + const FRAC_PI_6: Self; + /// π/8 + const FRAC_PI_8: Self; + + /// Computes the sine of a number (in radians). + fn sin(self) -> Self; + /// Computes the cosine of a number (in radians). + fn cos(self) -> Self; + /// Computes the tangent of a number (in radians). + fn tan(self) -> Self; + /// Simultaneously computes the sine and cosine of the number, `x`. Returns `(sin(x), cos(x))`. + fn sin_cos(self) -> (Self, Self); + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. + /// + /// - `x = 0`, `y = 0`: `0` + /// - `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// - `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// - `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + fn atan2(self, other: Self) -> Self; + /// Converts radians to degrees. + fn to_degrees(self) -> Self; + /// Converts degrees to radians. + fn to_radians(self) -> Self; + /// Computes the absolute value of `self`. + fn abs(self) -> Self; + /// Returns the minimum of the two numbers, ignoring NaN. + fn min(self, other: Self) -> Self; + /// Returns the maximum of the two numbers, ignoring NaN. + fn max(self, other: Self) -> Self; +} + +impl Float for f32 { + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + const NEG_ONE: Self = -1.0; + const TAU: Self = std::f32::consts::TAU; + const PI: Self = std::f32::consts::PI; + const FRAC_PI_2: Self = std::f32::consts::FRAC_PI_2; + const FRAC_PI_3: Self = std::f32::consts::FRAC_PI_3; + const FRAC_PI_4: Self = std::f32::consts::FRAC_PI_4; + const FRAC_PI_6: Self = std::f32::consts::FRAC_PI_6; + const FRAC_PI_8: Self = std::f32::consts::FRAC_PI_8; + + fn sin(self) -> Self { + self.sin() + } + fn cos(self) -> Self { + self.cos() + } + fn tan(self) -> Self { + self.tan() + } + fn sin_cos(self) -> (Self, Self) { + self.sin_cos() + } + fn atan2(self, other: Self) -> Self { + self.atan2(other) + } + fn to_degrees(self) -> Self { + self.to_degrees() + } + fn to_radians(self) -> Self { + self.to_radians() + } + fn abs(self) -> Self { + self.abs() + } + fn min(self, other: Self) -> Self { + self.min(other) + } + fn max(self, other: Self) -> Self { + self.max(other) + } +} + +impl Float for f64 { + const ZERO: Self = 0.0; + const ONE: Self = 1.0; + const NEG_ONE: Self = -1.0; + const TAU: Self = std::f64::consts::TAU; + const PI: Self = std::f64::consts::PI; + const FRAC_PI_2: Self = std::f64::consts::FRAC_PI_2; + const FRAC_PI_3: Self = std::f64::consts::FRAC_PI_3; + const FRAC_PI_4: Self = std::f64::consts::FRAC_PI_4; + const FRAC_PI_6: Self = std::f64::consts::FRAC_PI_6; + const FRAC_PI_8: Self = std::f64::consts::FRAC_PI_8; + + fn sin(self) -> Self { + self.sin() + } + fn cos(self) -> Self { + self.cos() + } + fn tan(self) -> Self { + self.tan() + } + fn sin_cos(self) -> (Self, Self) { + self.sin_cos() + } + fn atan2(self, other: Self) -> Self { + self.atan2(other) + } + fn to_degrees(self) -> Self { + self.to_degrees() + } + fn to_radians(self) -> Self { + self.to_radians() + } + fn abs(self) -> Self { + self.abs() + } + fn min(self, other: Self) -> Self { + self.min(other) + } + fn max(self, other: Self) -> Self { + self.max(other) + } +} diff --git a/crates/bevy_math/src/lib.rs b/crates/bevy_math/src/lib.rs index c6fb416d7eacf..751389b41715b 100644 --- a/crates/bevy_math/src/lib.rs +++ b/crates/bevy_math/src/lib.rs @@ -7,13 +7,16 @@ #![warn(missing_docs)] mod affine3; +mod angle; mod aspect_ratio; pub mod cubic_splines; +pub mod float; pub mod primitives; mod ray; mod rects; pub use affine3::*; +pub use angle::Angle; pub use aspect_ratio::AspectRatio; pub use ray::{Ray2d, Ray3d}; pub use rects::*; @@ -26,8 +29,8 @@ pub mod prelude { CubicBSpline, CubicBezier, CubicCardinalSpline, CubicGenerator, CubicHermite, CubicSegment, }, - primitives, BVec2, BVec3, BVec4, EulerRot, IRect, IVec2, IVec3, IVec4, Mat2, Mat3, Mat4, - Quat, Ray2d, Ray3d, Rect, URect, UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3, + primitives, Angle, BVec2, BVec3, BVec4, EulerRot, IRect, IVec2, IVec3, IVec4, Mat2, Mat3, + Mat4, Quat, Ray2d, Ray3d, Rect, URect, UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles, }; } diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index c67d0cfe578cd..00a5a882dc994 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use bevy_ecs::prelude::*; use bevy_math::{ - AspectRatio, Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles, + Angle, AspectRatio, Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles, }; use bevy_reflect::prelude::*; use bevy_render::{ @@ -107,12 +107,12 @@ pub struct SpotLight { /// `outer_angle` should be < `PI / 2.0`. /// `PI / 2.0` defines a hemispherical spot light, but shadows become very blocky as the angle /// approaches this limit. - pub outer_angle: f32, + pub outer_angle: Angle, /// Angle defining the distance from the spot light direction to the inner limit /// of the light's cone of effect. /// Light is attenuated from `inner_angle` to `outer_angle` to give a smooth falloff. /// `inner_angle` should be <= `outer_angle` - pub inner_angle: f32, + pub inner_angle: Angle, } impl SpotLight { @@ -131,8 +131,8 @@ impl Default for SpotLight { shadows_enabled: false, shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS, shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS, - inner_angle: 0.0, - outer_angle: std::f32::consts::FRAC_PI_4, + inner_angle: Angle::ZERO, + outer_angle: Angle::FRAC_PI_4, } } } @@ -1155,7 +1155,7 @@ pub(crate) struct PointLightAssignmentData { transform: GlobalTransform, range: f32, shadows_enabled: bool, - spot_light_angle: Option, + spot_light_angle: Option>, render_layers: RenderLayers, } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 9b9b635ab0f83..9d948b7e53f15 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, 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<(Angle, Angle)>, } #[derive(Component, Debug)] @@ -635,9 +635,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: Angle) -> 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.as_radians() * 2.0, 1.0, POINT_LIGHT_NEAR_Z) } #[allow(clippy::too_many_arguments)] diff --git a/crates/bevy_reflect/src/impls/angle.rs b/crates/bevy_reflect/src/impls/angle.rs new file mode 100644 index 0000000000000..a5ec8d63765ca --- /dev/null +++ b/crates/bevy_reflect/src/impls/angle.rs @@ -0,0 +1,6 @@ +use crate as bevy_reflect; +use crate::prelude::ReflectDefault; +use bevy_math::float::Float; +use bevy_reflect_derive::impl_reflect_value; + +impl_reflect_value!(::bevy_math::Angle(Debug, Default)); diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 3ed140c6f207b..d0900a59b7510 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -490,6 +490,7 @@ mod impls { #[cfg(feature = "smol_str")] mod smol_str; + mod angle; mod std; mod uuid; } diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 316ee97719d7e..43a29caadc920 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::Angle; 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: Angle) { + self.rotate(Quat::from_axis_angle(axis, angle.as_radians())); } - /// 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: Angle) { + self.rotate(Quat::from_rotation_x(angle.as_radians())); } - /// 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: Angle) { + self.rotate(Quat::from_rotation_y(angle.as_radians())); } - /// 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: Angle) { + self.rotate(Quat::from_rotation_z(angle.as_radians())); } /// 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: Angle) { + self.rotate_local(Quat::from_axis_angle(axis, angle.as_radians())); } - /// 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: Angle) { + self.rotate_local(Quat::from_rotation_x(angle.as_radians())); } - /// 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: Angle) { + self.rotate_local(Quat::from_rotation_y(angle.as_radians())); } - /// 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: Angle) { + self.rotate_local(Quat::from_rotation_z(angle.as_radians())); } /// Translates this [`Transform`] around a `point` in space. diff --git a/crates/bevy_winit/src/converters.rs b/crates/bevy_winit/src/converters.rs index 9817d5a4e98ae..1daef6d1334e8 100644 --- a/crates/bevy_winit/src/converters.rs +++ b/crates/bevy_winit/src/converters.rs @@ -5,7 +5,7 @@ use bevy_input::{ touch::{ForceTouch, TouchInput, TouchPhase}, ButtonState, }; -use bevy_math::Vec2; +use bevy_math::{Angle, Vec2}; use bevy_window::{CursorIcon, EnabledButtons, WindowLevel, WindowTheme}; pub fn convert_keyboard_input( @@ -57,7 +57,7 @@ pub fn convert_touch_input( } => ForceTouch::Calibrated { force, max_possible_force, - altitude_angle, + altitude_angle: altitude_angle.map(Angle::radians), }, winit::event::Force::Normalized(x) => ForceTouch::Normalized(x), }), diff --git a/examples/2d/2d_gizmos.rs b/examples/2d/2d_gizmos.rs index d3dcd7c960f6a..95a63b087cc6b 100644 --- a/examples/2d/2d_gizmos.rs +++ b/examples/2d/2d_gizmos.rs @@ -52,7 +52,13 @@ fn system(mut gizmos: Gizmos, time: Res