# Objective
- `Rotation2d` is a very long name for a commonly used type.
## Solution
- Rename it to `Rot2` to match `glam`'s naming convention (e.g. `Vec2`)
I ran a poll, and `Rot2` was the favorite of the candidate names.
This is not actually a breaking change, since `Rotation2d` has not been
shipped yet.
---------
Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
# Objective
Fixes#13535.
## Solution
I implemented `Reflect` for close to all math types now, except for some
types that it would cause issues (like some boxed types).
## Testing
- Everything seems to still build, will await CI though.
---
## Changelog
- Made close to all math types implement `Reflect`.
# Objective
- People have reported bounding volumes being slower than their existing
solution because it doesn't use SIMD aligned types.
## Solution
- Use `Vec3A` internally for bounding volumes, accepting `Into<Vec3A>`
wherever possible
- Change some code to make it more likely SIMD operations are used.
---
## Changelog
- Use `Vec3A` for 3D bounding volumes and raycasts
## Migration Guide
- 3D bounding volumes now use `Vec3A` types internally, return values
from methods on them now return `Vec3A` instead of `Vec3`
# Objective
Add a `scale_around_center` method to the `BoundingVolume` trait, as per
#12130.
## Solution
Added `scale_around_center` to the `BoundingVolume` trait, implemented
in `Aabb2d`, `Aabb3d`, `BoundingCircle`, and `BoundingSphere` (with
tests).
# Objective
Rotating vectors is a very common task. It is required for a variety of
things both within Bevy itself and in many third party plugins, for
example all over physics and collision detection, and for things like
Bevy's bounding volumes and several gizmo implementations.
For 3D, we can do this using a `Quat`, but for 2D, we do not have a
clear and efficient option. `Mat2` can be used for rotating vectors if
created using `Mat2::from_angle`, but this is not obvious to many users,
it doesn't have many rotation helpers, and the type does not give any
guarantees that it represents a valid rotation.
We should have a proper type for 2D rotations. In addition to allowing
for potential optimization, it would allow us to have a consistent and
explicitly documented representation used throughout the engine, i.e.
counterclockwise and in radians.
## Representation
The mathematical formula for rotating a 2D vector is the following:
```
new_x = x * cos - y * sin
new_y = x * sin + y * cos
```
Here, `sin` and `cos` are the sine and cosine of the rotation angle.
Computing these every time when a vector needs to be rotated can be
expensive, so the rotation shouldn't be just an `f32` angle. Instead, it
is often more efficient to represent the rotation using the sine and
cosine of the angle instead of storing the angle itself. This can be
freely passed around and reused without unnecessary computations.
The two options are either a 2x2 rotation matrix or a unit complex
number where the cosine is the real part and the sine is the imaginary
part. These are equivalent for the most part, but the unit complex
representation is a bit more memory efficient (two `f32`s instead of
four), so I chose that. This is like Nalgebra's
[`UnitComplex`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.UnitComplex.html)
type, which can be used for the
[`Rotation2`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.Rotation2.html)
type.
## Implementation
Add a `Rotation2d` type represented as a unit complex number:
```rust
/// A counterclockwise 2D rotation in radians.
///
/// The rotation angle is wrapped to be within the `]-pi, pi]` range.
pub struct Rotation2d {
/// The cosine of the rotation angle in radians.
///
/// This is the real part of the unit complex number representing the rotation.
pub cos: f32,
/// The sine of the rotation angle in radians.
///
/// This is the imaginary part of the unit complex number representing the rotation.
pub sin: f32,
}
```
Using it is similar to using `Quat`, but in 2D:
```rust
let rotation = Rotation2d::radians(PI / 2.0);
// Rotate vector (also works on Direction2d!)
assert_eq!(rotation * Vec2::X, Vec2::Y);
// Get angle as degrees
assert_eq!(rotation.as_degrees(), 90.0);
// Getting sin and cos is free
let (sin, cos) = rotation.sin_cos();
// "Subtract" rotations
let rotation2 = Rotation2d::FRAC_PI_4; // there are constants!
let diff = rotation * rotation2.inverse();
assert_eq!(diff.as_radians(), PI / 4.0);
// This is equivalent to the above
assert_eq!(rotation2.angle_between(rotation), PI / 4.0);
// Lerp
let rotation1 = Rotation2d::IDENTITY;
let rotation2 = Rotation2d::FRAC_PI_2;
let result = rotation1.lerp(rotation2, 0.5);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_4);
// Slerp
let rotation1 = Rotation2d::FRAC_PI_4);
let rotation2 = Rotation2d::degrees(-180.0); // we can use degrees too!
let result = rotation1.slerp(rotation2, 1.0 / 3.0);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_2);
```
There's also a `From<f32>` implementation for `Rotation2d`, which means
that methods can still accept radians as floats if the argument uses
`impl Into<Rotation2d>`. This means that adding `Rotation2d` shouldn't
even be a breaking change.
---
## Changelog
- Added `Rotation2d`
- Bounding volume methods now take an `impl Into<Rotation2d>`
- Gizmo methods with rotation now take an `impl Into<Rotation2d>`
## Future use cases
- Collision detection (a type like this is quite essential considering
how common vector rotations are)
- `Transform` helpers (e.g. return a 2D rotation about the Z axis from a
`Transform`)
- The rotation used for `Transform2d` (#8268)
- More gizmos, maybe meshes... everything in 2D that uses rotation
---------
Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Co-authored-by: Robert Walter <robwalter96@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
# Objective
Make it straightforward to translate and rotate bounding volumes.
## Solution
Add `translate_by`/`translated_by`, `rotate_by`/`rotated_by`,
`transform_by`/`transformed_by` methods to the `BoundingVolume` trait.
This follows the naming used for mesh transformations (see #11454 and
#11675).
---
## Changelog
- Added `translate_by`/`translated_by`, `rotate_by`/`rotated_by`,
`transform_by`/`transformed_by` methods to the `BoundingVolume` trait
and implemented them for the bounding volumes
- Renamed `Position` associated type to `Translation`
---------
Co-authored-by: Mateusz Wachowiak <mateusz_wachowiak@outlook.com>
# Objective
- Add a basic form of shapecasting for bounding volumes
## Solution
- Implement AabbCast2d, AabbCast3d, BoundingCircleCast, and
BoundingSphereCast
- These are really just raycasts, but they modify the volumes the ray is
casting against
- The tests are slightly simpler, since they just use the raycast code
for the heavy lifting
# Objective
#10946 added bounding volume types and an `IntersectsVolume` trait, but
didn't actually implement intersections between bounding volumes.
This PR implements AABB-AABB, circle-circle / sphere-sphere, and
AABB-circle / AABB-sphere intersections.
## Solution
Implement `IntersectsVolume` for bounding volume pairs. I also added
`closest_point` methods to return the closest point on the surface /
inside of bounding volumes. This is used for AABB-circle / AABB-sphere
intersections.
---------
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
# Objective
Currently, the only way to create an AABB is to specify its `min` and
`max` coordinates. However, it's often more useful to use the center and
half-size instead.
## Solution
Add `new` constructors for `Aabb2d` and `Aabb3d`.
This:
```rust
let aabb = Aabb3d {
min: center - half_size,
max: center + half_size,
}
```
becomes this:
```rust
let aabb = Aabb3d::new(center, half_size);
```
I also made the usage of "half-extents" vs. "half-size" a bit more
consistent.
# Objective
Closes#10570.
#10946 added bounding volume types and traits, but didn't use them for
anything yet. This PR implements `Bounded2d` and `Bounded3d` for Bevy's
primitive shapes.
## Solution
Implement `Bounded2d` and `Bounded3d` for primitive shapes. This allows
computing AABBs and bounding circles/spheres for them.
For most shapes, there are several ways of implementing bounding
volumes. I took inspiration from [Parry's bounding
volumes](https://github.com/dimforge/parry/tree/master/src/bounding_volume),
[Inigo Quilez](http://iquilezles.org/articles/diskbbox/), and figured
out the rest myself using geometry. I tried to comment all slightly
non-trivial or unclear math to make it understandable.
Parry uses support mapping (finding the farthest point in some direction
for convex shapes) for some AABBs like cones, cylinders, and line
segments. This involves several quat operations and normalizations, so I
opted for the simpler and more efficient geometric approaches shown in
[Quilez's article](http://iquilezles.org/articles/diskbbox/).
Below you can see some of the bounding volumes working in 2D and 3D.
Note that I can't conveniently add these examples yet because they use
primitive shape meshing, which is still WIP.
https://github.com/bevyengine/bevy/assets/57632562/4465cbc6-285b-4c71-b62d-a2b3ee16f8b4https://github.com/bevyengine/bevy/assets/57632562/94b4ac84-a092-46d7-b438-ce2e971496a4
---
## Changelog
- Implemented `Bounded2d`/`Bounded3d` for primitive shapes
- Added `from_point_cloud` method for bounding volumes (used by many
bounding implementations)
- Added `point_cloud_2d/3d_center` and `rotate_vec2` utility functions
- Added `RegularPolygon::vertices` method (used in regular polygon AABB
construction)
- Added `Triangle::circumcenter` method (used in triangle bounding
circle construction)
- Added bounding circle/sphere creation from AABBs and vice versa
## Extra
Do we want to implement `Bounded2d` for some "3D-ish" shapes too? For
example, capsules are sort of dimension-agnostic and useful for 2D, so I
think that would be good to implement. But a cylinder in 2D is just a
rectangle, and a cone is a triangle, so they wouldn't make as much sense
to me. A conical frustum would be an isosceles trapezoid, which could be
useful, but I'm not sure if computing the 2D AABB of a 3D frustum makes
semantic sense.