Commit graph

226 commits

Author SHA1 Message Date
targrub
8316166622
Fix uses of "it's" vs "its". (#13033)
Grammar changes only.
2024-04-19 18:17:31 +00:00
Lynn
cd80b10d43
Math primitives cleanup (#13020)
# Objective

- General clenup of the primitives in `bevy_math`
- Add `eccentricity()` to `Ellipse`

## Solution

- Moved `Bounded3d` implementation for `Triangle3d` to the `bounded`
module
- Added `eccentricity()` to `Ellipse`
- `Ellipse::semi_major()` and `::semi_minor()` now accept `&self`
instead of `self`
- `Triangle3d::is_degenerate()` actually uses `f32::EPSILON` as
documented
- Added tests for `Triangle3d`-maths

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
Co-authored-by: Miles Silberling-Cook <nth.tensor@gmail.com>
2024-04-18 23:45:51 +00:00
andristarr
2b3e3341d6
separating finite and infinite 3d planes (#12426)
# Objective

Fixes #12388

## Solution

- Removing the plane3d and adding rect3d primitive mesh
2024-04-18 14:13:22 +00:00
Matty
3a7923ea92
Random sampling of directions and quaternions (#12857)
# Objective

Augment Bevy's random sampling capabilities by providing good tools for
producing random directions and rotations.

## Solution

The `rand` crate has a natural tool for providing `Distribution`s whose
output is a type that doesn't require any additional data to sample
values — namely,
[`Standard`](https://docs.rs/rand/latest/rand/distributions/struct.Standard.html).

Here, our existing `ShapeSample` implementations have been put to good
use in providing these, resulting in patterns like the following:
```rust
// Using thread-local rng
let random_direction1: Dir3 = random();

// Using an explicit rng
let random_direction2: Dir3 = rng.gen();

// Using an explicit rng coupled explicitly with Standard
let random_directions: Vec<Dir3> = rng.sample_iter(Standard).take(5).collect();
```

Furthermore, we have introduced a trait `FromRng` which provides sugar
for `rng.gen()` that is more namespace-friendly (in this author's
opinion):
```rust
let random_direction = Dir3::from_rng(rng);
```

The types this has been implemented for are `Dir2`, `Dir3`, `Dir3A`, and
`Quat`. Notably, `Quat` uses `glam`'s implementation rather than an
in-house one, and as a result, `bevy_math`'s "rand" feature now enables
that of `glam`.

---

## Changelog

- Created `standard` submodule in `sampling` to hold implementations and
other items related to the `Standard` distribution.
- "rand" feature of `bevy_math` now enables that of `glam`.

---

## Discussion

From a quick glance at `Quat`'s distribution implementation in `glam`, I
am a bit suspicious, since it is simple and doesn't match any algorithm
that I came across in my research. I will do a little more digging as a
follow-up to this and see if it's actually uniform (maybe even using
those tools I wrote — what a thrill).

As an aside, I'd also like to say that I think
[`Distribution`](https://docs.rs/rand/latest/rand/distributions/trait.Distribution.html)
is really, really good. It integrates with distributions provided
externally (e.g. in `rand` itself and its extensions) along with doing a
good job of isolating the source of randomness, so that output can be
reliably reproduced if need be. Finally, `Distribution::sample_iter` is
quite good for ergonomically acquiring lots of random values. At one
point I found myself writing traits to describe random sampling and
essentially reinvented this one. I just think it's good, and I think
it's worth centralizing around to a significant extent.
2024-04-04 23:13:00 +00:00
Antony
344e28d095
Change Tetrahedron default origin to (0, 0, 0) (#12867)
# Objective

- Fixes #12837.

## Solution

- Update `Tetrahedron` default vertices to `[0.5, 0.5, 0.5]`, `[-0.5,
0.5, -0.5]`, `[-0.5, -0.5, 0.5]` and `[0.5, -0.5, -0.5]` respectively.
- Update `tetrahedron_math` tests to account for change in default
vertices.
2024-04-03 23:00:54 +00:00
mamekoro
8092e2c86d
Implement basic traits for AspectRatio (#12840)
# Objective
`AspectRatio` is a newtype of `f32`, so it can implement basic traits;
`Copy`, `Clone`, `Debug`, `PartialEq` and `PartialOrd`.

## Solution
Derive basic traits for `AspectRatio`.
2024-04-01 23:02:07 +00:00
Jakub Marcowski
20ee56e719
Add Tetrahedron primitive to bevy_math::primitives (#12688)
# Objective

- #10572

There is no 3D primitive available for the common shape of a tetrahedron
(3-simplex).

## Solution

This PR introduces a new type to the existing math primitives:

- `Tetrahedron`: a polyhedron composed of four triangular faces, six
straight edges, and four vertices

---

## Changelog

### Added

- `Tetrahedron` primitive to the `bevy_math` crate
- `Tetrahedron` tests (`area`, `volume` methods)
- `impl_reflect!` declaration for `Tetrahedron` in the `bevy_reflect`
crate
2024-04-01 21:53:12 +00:00
BD103
84363f2fab
Remove redundant imports (#12817)
# Objective

- There are several redundant imports in the tests and examples that are
not caught by CI because additional flags need to be passed.

## Solution

- Run `cargo check --workspace --tests` and `cargo check --workspace
--examples`, then fix all warnings.
- Add `test-check` to CI, which will be run in the check-compiles job.
This should catch future warnings for tests. Examples are already
checked, but I'm not yet sure why they weren't caught.

## Discussion

- Should the `--tests` and `--examples` flags be added to CI, so this is
caught in the future?
- If so, #12818 will need to be merged first. It was also a warning
raised by checking the examples, but I chose to split off into a
separate PR.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-04-01 19:59:08 +00:00
Verte
97f0555cb0
Remove VectorSpace impl on Quat (#12796)
- Fixes #[12762](https://github.com/bevyengine/bevy/issues/12762).

## Migration Guide

- `Quat` no longer implements `VectorSpace` as unit quaternions don't
actually form proper vector spaces. If you're absolutely certain that
what you're doing is correct, convert the `Quat` into a `Vec4` and
perform the operations before converting back.
2024-03-30 17:18:52 +00:00
Matty
bcdb20d4f3
Fix Triangle2d/Triangle3d interior sampling to correctly follow triangle (#12766)
# Objective

When I wrote #12747 I neglected to translate random samples from
triangles back to the point where they originated, so they would be
sampled near the origin instead of at the actual triangle location.

## Solution

Translate by the first vertex location so that the samples follow the
actual triangle.
2024-03-29 13:10:23 +00:00
Matty
f924b4d9ef
Move Point out of cubic splines module and expand it (#12747)
# Objective

Previously, the `Point` trait, which abstracts all of the operations of
a real vector space, was sitting in the submodule of `bevy_math` for
cubic splines. However, the trait has broader applications than merely
cubic splines, and we should use it when possible to avoid code
duplication when performing vector operations.

## Solution

`Point` has been moved into a new submodule in `bevy_math` named
`common_traits`. Furthermore, it has been renamed to `VectorSpace`,
which is more descriptive, and an additional trait `NormedVectorSpace`
has been introduced to expand the API to cover situations involving
geometry in addition to algebra. Additionally, `VectorSpace` itself now
requires a `ZERO` constant and `Neg`. It also supports a `lerp` function
as an automatic trait method.

Here is what that looks like:
```rust
/// A type that supports the mathematical operations of a real vector space, irrespective of dimension.
/// In particular, this means that the implementing type supports:
/// - Scalar multiplication and division on the right by elements of `f32`
/// - Negation
/// - Addition and subtraction
/// - Zero
///
/// Within the limitations of floating point arithmetic, all the following are required to hold:
/// - (Associativity of addition) For all `u, v, w: Self`, `(u + v) + w == u + (v + w)`.
/// - (Commutativity of addition) For all `u, v: Self`, `u + v == v + u`.
/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`.
/// - (Additive inverse) For all `v: Self`, `v - v == v + (-v) == Self::ZERO`.
/// - (Compatibility of multiplication) For all `a, b: f32`, `v: Self`, `v * (a * b) == (v * a) * b`.
/// - (Multiplicative identity) For all `v: Self`, `v * 1.0 == v`.
/// - (Distributivity for vector addition) For all `a: f32`, `u, v: Self`, `(u + v) * a == u * a + v * a`.
/// - (Distributivity for scalar addition) For all `a, b: f32`, `v: Self`, `v * (a + b) == v * a + v * b`.
///
/// Note that, because implementing types use floating point arithmetic, they are not required to actually
/// implement `PartialEq` or `Eq`.
pub trait VectorSpace:
    Mul<f32, Output = Self>
    + Div<f32, Output = Self>
    + Add<Self, Output = Self>
    + Sub<Self, Output = Self>
    + Neg
    + Default
    + Debug
    + Clone
    + Copy
{
    /// The zero vector, which is the identity of addition for the vector space type.
    const ZERO: Self;

    /// Perform vector space linear interpolation between this element and another, based
    /// on the parameter `t`. When `t` is `0`, `self` is recovered. When `t` is `1`, `rhs`
    /// is recovered.
    ///
    /// Note that the value of `t` is not clamped by this function, so interpolating outside
    /// of the interval `[0,1]` is allowed.
    #[inline]
    fn lerp(&self, rhs: Self, t: f32) -> Self {
        *self * (1. - t) + rhs * t
    }
}
```
```rust
/// A type that supports the operations of a normed vector space; i.e. a norm operation in addition
/// to those of [`VectorSpace`]. Specifically, the implementor must guarantee that the following
/// relationships hold, within the limitations of floating point arithmetic:
/// - (Nonnegativity) For all `v: Self`, `v.norm() >= 0.0`.
/// - (Positive definiteness) For all `v: Self`, `v.norm() == 0.0` implies `v == Self::ZERO`.
/// - (Absolute homogeneity) For all `c: f32`, `v: Self`, `(v * c).norm() == v.norm() * c.abs()`.
/// - (Triangle inequality) For all `v, w: Self`, `(v + w).norm() <= v.norm() + w.norm()`.
///
/// Note that, because implementing types use floating point arithmetic, they are not required to actually
/// implement `PartialEq` or `Eq`.
pub trait NormedVectorSpace: VectorSpace {
    /// The size of this element. The return value should always be nonnegative.
    fn norm(self) -> f32;

    /// The squared norm of this element. Computing this is often faster than computing
    /// [`NormedVectorSpace::norm`].
    #[inline]
    fn norm_squared(self) -> f32 {
        self.norm() * self.norm()
    }

    /// The distance between this element and another, as determined by the norm.
    #[inline]
    fn distance(self, rhs: Self) -> f32 {
        (rhs - self).norm()
    }

    /// The squared distance between this element and another, as determined by the norm. Note that
    /// this is often faster to compute in practice than [`NormedVectorSpace::distance`].
    #[inline]
    fn distance_squared(self, rhs: Self) -> f32 {
        (rhs - self).norm_squared()
    }
}
```

Furthermore, this PR also demonstrates the use of the
`NormedVectorSpace` combined API to implement `ShapeSample` for
`Triangle2d` and `Triangle3d` simultaneously. Such deduplication is one
of the drivers for developing these APIs.

---

## Changelog

- `Point` from `cubic_splines` becomes `VectorSpace`, exported as
`bevy::math::VectorSpace`.
- `VectorSpace` requires `Neg` and `VectorSpace::ZERO` in addition to
its existing prerequisites.
- Introduced public traits `bevy::math::NormedVectorSpace` for generic
geometry tasks involving vectors.
- Implemented `ShapeSample` for `Triangle2d` and `Triangle3d`.

## Migration Guide

Since `Point` no longer exists, any projects using it must switch to
`bevy::math::VectorSpace`. Additionally, third-party implementations of
this trait now require the `Neg` trait; the constant `VectorSpace::ZERO`
must be provided as well.

---

## Discussion

### Design considerations

Originally, the `NormedVectorSpace::norm` method was part of a separate
trait `Normed`. However, I think that was probably too broad and, more
importantly, the semantics of having it in `NormedVectorSpace` are much
clearer.

As it currently stands, the API exposed here is pretty minimal, and
there is definitely a lot more that we could do, but there are more
questions to answer along the way. As a silly example, we could
implement `NormedVectorSpace::length` as an alias for
`NormedVectorSpace::norm`, but this overlaps with methods in all of the
glam types, so we would want to make sure that the implementations are
effectively identical (for what it's worth, I think they are already).

### Future directions

One example of something that could belong in the `NormedVectorSpace`
API is normalization. Actually, such a thing previously existed on this
branch before I decided to shelve it because of concerns with namespace
collision. It looked like this:
```rust
/// This element, but normalized to norm 1 if possible. Returns an error when the reciprocal of
/// the element's norm is not finite.
#[inline]
#[must_use]
fn normalize(&self) -> Result<Self, NonNormalizableError> {
    let reciprocal = 1.0 / self.norm();
    if reciprocal.is_finite() {
        Ok(*self * reciprocal)
    } else {
        Err(NonNormalizableError { reciprocal })
    }
}

/// An error indicating that an element of a [`NormedVectorSpace`] was non-normalizable due to having 
/// non-finite norm-reciprocal.
#[derive(Debug, Error)]
#[error("Element with norm reciprocal {reciprocal} cannot be normalized")]
pub struct NonNormalizableError {
    reciprocal: f32
}
```

With this kind of thing in hand, it might be worth considering
eventually making the passage from vectors to directions fully generic
by employing a wrapper type. (Of course, for our concrete types, we
would leave the existing names in place as aliases.) That is, something
like:
```rust
pub struct NormOne<T>
where T: NormedVectorSpace { //... }
```

Utterly separately, the reason that I implemented `ShapeSample` for
`Triangle2d`/`Triangle3d` was to prototype uniform sampling of abstract
meshes, so that's also a future direction.

---------

Co-authored-by: Zachary Harrold <zac@harrold.com.au>
2024-03-28 13:40:26 +00:00
mamekoro
6840f95d62
Implement From<Vec2> for AspectRatio (#12754)
# Objective
Since it is common to store a pair of width and height as `Vec2`, it
would be useful to have an easy way to instantiate `AspectRatio` from
`Vec2`.

## Solution
Add `impl From<Vec2> for AspectRatio`.

---

## Changelog
- Added `impl From<Vec2> for AspectRatio`
2024-03-27 22:32:31 +00:00
Vitaliy Sapronenko
c38e2d037d
Math tests fix (#12748)
# Objective

Fixes `cargo test -p bevy_math` as in #12729.

## Solution

As described in
[message](https://github.com/bevyengine/bevy/issues/12729#issuecomment-2022197944)
Added workaround `bevy_math = { path = ".", version = "0.14.0-dev",
features = ["approx"] }` to `bevy_math`'s `dev-dependencies`

---------

Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
2024-03-27 20:48:20 +00:00
Jacques Schutte
4508077297
Move FloatOrd into bevy_math (#12732)
# Objective

- Fixes #12712

## Solution

- Move the `float_ord.rs` file to `bevy_math`
- Change any `bevy_utils::FloatOrd` statements to `bevy_math::FloatOrd`

---

## Changelog

- Moved `FloatOrd` from `bevy_utils` to `bevy_math`

## Migration Guide

- References to `bevy_utils::FloatOrd` should be changed to
`bevy_math::FloatOrd`
2024-03-27 18:30:11 +00:00
James Liu
56bcbb0975
Forbid unsafe in most crates in the engine (#12684)
# Objective
Resolves #3824. `unsafe` code should be the exception, not the norm in
Rust. It's obviously needed for various use cases as it's interfacing
with platforms and essentially running the borrow checker at runtime in
the ECS, but the touted benefits of Bevy is that we are able to heavily
leverage Rust's safety, and we should be holding ourselves accountable
to that by minimizing our unsafe footprint.

## Solution
Deny `unsafe_code` workspace wide. Add explicit exceptions for the
following crates, and forbid it in almost all of the others.

* bevy_ecs - Obvious given how much unsafe is needed to achieve
performant results
* bevy_ptr - Works with raw pointers, even more low level than bevy_ecs.
 * bevy_render - due to needing to integrate with wgpu
 * bevy_window - due to needing to integrate with raw_window_handle
* bevy_utils - Several unsafe utilities used by bevy_ecs. Ideally moved
into bevy_ecs instead of made publicly usable.
 * bevy_reflect - Required for the unsafe type casting it's doing.
 * bevy_transform - for the parallel transform propagation
 * bevy_gizmos  - For the SystemParam impls it has.
* bevy_assets - To support reflection. Might not be required, not 100%
sure yet.
* bevy_mikktspace - due to being a conversion from a C library. Pending
safe rewrite.
* bevy_dynamic_plugin - Inherently unsafe due to the dynamic loading
nature.

Several uses of unsafe were rewritten, as they did not need to be using
them:

* bevy_text - a case of `Option::unchecked` could be rewritten as a
normal for loop and match instead of an iterator.
* bevy_color - the Pod/Zeroable implementations were replaceable with
bytemuck's derive macros.
2024-03-27 03:30:08 +00:00
Jakub Marcowski
31d91466b4
Add Annulus primitive to bevy_math::primitives (#12706)
# Objective

- #10572

There is no 2D primitive available for the common shape of an annulus
(ring).

## Solution

This PR introduces a new type to the existing math primitives:

- `Annulus`: the region between two concentric circles

---

## Changelog

### Added

- `Annulus` primitive to the `bevy_math` crate
- `Annulus` tests (`diameter`, `thickness`, `area`, `perimeter` and
`closest_point` methods)

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-03-25 23:13:14 +00:00
James Liu
f096ad4155
Set the logo and favicon for all of Bevy's published crates (#12696)
# Objective
Currently the built docs only shows the logo and favicon for the top
level `bevy` crate. This makes views like
https://docs.rs/bevy_ecs/latest/bevy_ecs/ look potentially unrelated to
the project at first glance.

## Solution
Reproduce the docs attributes for every crate that Bevy publishes.

Ideally this would be done with some workspace level Cargo.toml control,
but AFAICT, such support does not exist.
2024-03-25 18:52:50 +00:00
Ame
72c51cdab9
Make feature(doc_auto_cfg) work (#12642)
# Objective

- In #12366 `![cfg_attr(docsrs, feature(doc_auto_cfg))] `was added. But
to apply it it needs `--cfg=docsrs` in rustdoc-args.


## Solution

- Apply `--cfg=docsrs` to all crates and CI.

I also added `[package.metadata.docs.rs]` to all crates to avoid adding
code behind a feature and forget adding the metadata.

Before:

![Screenshot 2024-03-22 at 00 51
57](https://github.com/bevyengine/bevy/assets/104745335/6a9dfdaa-8710-4784-852b-5f9b74e3522c)

After:
![Screenshot 2024-03-22 at 00 51
32](https://github.com/bevyengine/bevy/assets/104745335/c5bd6d8e-8ddb-45b3-b844-5ecf9f88961c)
2024-03-23 02:22:52 +00:00
Vitor Falcao
c9ec95d782
Add Triangle3d primitive to bevy_math::primitives (#12508)
# Context

[GitHub Discussion
Link](https://github.com/bevyengine/bevy/discussions/12506)

# Objective

- **Clarity:** More explicit representation of a common geometric
primitive.
- **Convenience:** Provide methods tailored to 3D triangles (area,
perimeters, etc.).

## Solution

- Adding the `Triangle3d` primitive into the `bevy_math` crate.

---

## Changelog

### Added

- `Triangle3d` primitive to the `bevy_math` crate

### Changed

- `Triangle2d::reverse`: the first and last vertices are swapped instead
of the second and third.

---------

Co-authored-by: Miles Silberling-Cook <NthTensor@users.noreply.github.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-03-22 17:24:51 +00:00
Matty
93c17d105a
Make cardinal splines include endpoints (#12574)
# Objective

- Fixes #12570 

## Solution

Previously, cardinal splines constructed by `CubicCardinalSpline` would
leave out their endpoints when constructing the cubic curve segments
connecting their points. (See the linked issue for details.)

Now, cardinal splines include the endpoints. For instance, the provided
usage example
```rust
let points = [
    vec2(-1.0, -20.0),
    vec2(3.0, 2.0),
    vec2(5.0, 3.0),
    vec2(9.0, 8.0),
];
let cardinal = CubicCardinalSpline::new(0.3, points).to_curve();
let positions: Vec<_> = cardinal.iter_positions(100).collect();
```
will actually produce a spline that connects all four of these points
instead of just the middle two "interior" points.

Internally, this is achieved by duplicating the endpoints of the vector
of control points before performing the construction of the associated
`CubicCurve`. This amounts to specifying that the tangents at the
endpoints `P_0` and `P_n` (say) should be parallel to `P_1 - P_0` and
`P_n - P_{n-1}`.

---

## Migration Guide

Any users relying on the old behavior of `CubicCardinalSpline` will have
to truncate any parametrizations they used in order to access a curve
identical to the one they had previously. This would be done by chopping
off a unit-distance segment from each end of the parametrizing interval.
For instance, if a user's existing code looks as follows
```rust
fn interpolate(t: f32) -> Vec2 {
    let points = [
        vec2(-1.0, -20.0),
        vec2(3.0, 2.0),
        vec2(5.0, 3.0),
        vec2(9.0, 8.0),
    ];
    let my_curve = CubicCardinalSpline::new(0.3, points).to_curve();
    my_curve.position(t)
}
```

then in order to obtain similar behavior, `t` will need to be shifted up
by 1, since the output of `CubicCardinalSpline::to_curve` has introduced
a new segment in the interval [0,1], displacing the old segment from
[0,1] to [1,2]:

```rust
fn interpolate(t: f32) -> Vec2 {
    let points = [
        vec2(-1.0, -20.0),
        vec2(3.0, 2.0),
        vec2(5.0, 3.0),
        vec2(9.0, 8.0),
    ];
    let my_curve = CubicCardinalSpline::new(0.3, points).to_curve();
    my_curve.position(t+1)
}
```

(Note that this does not provide identical output for values of `t`
outside of the interval [0,1].)

On the other hand, any user who was specifying additional endpoint
tangents simply to get the curve to pass through the right points (i.e.
not requiring exactly the same output) can simply omit the endpoints
that were being supplied only for control purposes.

---

## Discussion

### Design considerations

This is one of the two approaches outlined in #12570 — in this PR, we
are basically declaring that the docs are right and the implementation
was flawed.

One semi-interesting question is how the endpoint tangents actually
ought to be defined when we include them, and another option considered
was mirroring the control points adjacent to the endpoints instead of
duplicating them, which would have had the advantage that the expected
length of the corresponding difference should be more similar to that of
the other difference-tangents, provided that the points are equally
spaced.

In this PR, the duplication method (which produces smaller tangents) was
chosen for a couple reasons:
- It seems to be more standard
- It is exceptionally simple to implement
- I was a little concerned that the aforementioned alternative would
result in some over-extrapolation

### An annoyance

If you look at the code, you'll see I was unable to find a satisfactory
way of doing this without allocating a new vector. This doesn't seem
like a big problem given the context, but it does bother me. In
particular, if there is some easy parallel to `slice::windows` for
iterators that doesn't pull in an external dependency, I would love to
know about it.
2024-03-21 18:58:51 +00:00
Brezak
ed44eb3913
Add a from Dir2 impl for Vec2 (#12594)
# Objective

Allow converting from `Dir2` to `Vec2` in generic code. Fixes #12529.

## Solution

Added a `From<Dir2>` impl for `Vec2`.
2024-03-20 14:21:50 +00:00
Multirious
70da903cec
Add methods to return the inner value for direction types (#12516)
# Objective

Currently in order to retrieve the inner values from direction types is
that you need to use the `Deref` trait or `From`/`Into`. `Deref` that is
currently implemented is an anti-pattern that I believe should be less
relied upon.
This pull-request add getters for retrieving the inner values for
direction types.

Advantages of getters:
- Let rust-analyzer to list out available methods for users to
understand better to on how to get the inner value. (This happens to me.
I really don't know how to get the value until I look through the source
code.)
- They are simple.
- Generally won't be ambiguous in most context. Traits such as
`From`/`Into` will require fully qualified syntax from time to time.
- Unsurprising result.

Disadvantages of getters:
- More verbose

Advantages of deref polymorphism:
- You reduce boilerplate for getting the value and call inner methods
by:
  ```rust
  let dir = Dir3::new(Vec3::UP).unwrap();
  // getting value
  let value = *dir;
  // instead of using getters
  let value = dir.vec3();

  // calling methods for the inner vector
  dir.xy();
  // instead of using getters
  dir.vec3().xy();
  ```

Disadvantages of deref polymorphism:
- When under more level of indirection, it will requires more
dereferencing which will get ugly in some part:
  ```rust
  // getting value
  let value = **dir;
  // instead of using getters
  let value = dir.vec3();

  // calling methods for the inner vector
  dir.xy();
  // instead of using getters
  dir.vec3().xy();
  ```

[More detail
here](https://rust-unofficial.github.io/patterns/anti_patterns/deref.html).


Edit: Update information for From/Into trait.
Edit: Advantages and disadvantages.

## Solution

Add `vec2` method for Dir2.
Add `vec3` method for Dir3.
Add `vec3a` method for Dir3A.
2024-03-18 17:49:58 +00:00
TheBigCheese
948ea3137a
Uniform point sampling methods for some primitive shapes. (#12484)
# Objective
Give easy methods for uniform point sampling in a variety of primitive
shapes (particularly useful for circles and spheres) because in a lot of
cases its quite easy to get wrong (non-uniform).

## Solution
Added the `ShapeSample` trait to `bevy_math` and implemented it for
`Circle`, `Sphere`, `Rectangle`, `Cuboid`, `Cylinder`, `Capsule2d` and
`Capsule3d`. There are a few other shapes it would be reasonable to
implement for like `Triangle`, `Ellipse` and `Torus` but I'm not
immediately sure how these would be implemented (other than rejection
which could be the best method, and could be more performant than some
of the solutions in this pr I'm not sure). This exposes the
`sample_volume` and `sample_surface` methods to get both a random point
from its interior or its surface. EDIT: Renamed `sample_volume` to
`sample_interior` and `sample_surface` to `sample_boundary`

This brings in `rand` as a default optional dependency (without default
features), and the methods take `&mut impl Rng` which allows them to use
any random source implementing `RngCore`.

---

## Changelog
### Added
Added the methods `sample_interior` and `sample_boundary` to a variety
of primitive shapes providing easy uniform point sampling.
2024-03-17 14:48:16 +00:00
Antony
686d354d28
Add scale_around_center method to BoundingVolume trait (#12142)
# 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).
2024-03-11 21:48:25 +00:00
Joona Aalto
f89af0567b
Add Rotation2d (#11658)
# 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>
2024-03-11 19:11:57 +00:00
Al M
52e3f2007b
Add "all-features = true" to docs.rs metadata for most crates (#12366)
# Objective

Fix missing `TextBundle` (and many others) which are present in the main
crate as default features but optional in the sub-crate. See:

- https://docs.rs/bevy/0.13.0/bevy/ui/node_bundles/index.html
- https://docs.rs/bevy_ui/0.13.0/bevy_ui/node_bundles/index.html

~~There are probably other instances in other crates that I could track
down, but maybe "all-features = true" should be used by default in all
sub-crates? Not sure.~~ (There were many.) I only noticed this because
rust-analyzer's "open docs" features takes me to the sub-crate, not the
main one.

## Solution

Add "all-features = true" to docs.rs metadata for crates that use
features.

## Changelog

### Changed

- Unified features documented on docs.rs between main crate and
sub-crates
2024-03-08 20:03:09 +00:00
Joona Aalto
4bed1b2200
Add note about rotations for Aabb3d (#12315)
# Objective

Fixes #12310.

#11681 added transformations for bounding volumes, but I accidentally
only added a note in the docs about repeated rotations for `Aabb2d` and
not `Aabb3d`.

## Solution

Copy the docs over to `Aabb3d`.
2024-03-05 17:22:53 +00:00
Joona Aalto
921ba54acf
Support transforming bounding volumes (#11681)
# 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>
2024-03-05 00:48:45 +00:00
Joona Aalto
983da7677a
Improve error messages for denormalized directions (#12278)
# Objective

`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.

Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).

The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.

## Solution

Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.

Here's what the error and warning look like:

```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```

```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```

I gave the same treatment to `new_unchecked`:

```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```

```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```

---

## Discussion

### Threshold values

The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.

### Logging

`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
Joona Aalto
6032978eba
Implement Mul between f32 and direction types (#12276)
# Objective

Bevy's `Dir3` and `Dir3A` only implement `Mul<f32>` and not vice versa,
and `Dir2` can not be multiplied by `f32` at all. They all should
implement multiplication both ways, just like Glam's vector types.

## Solution

Implement `Mul<Dir2>`, `Mul<Dir3>`, and `Mul<Dir3A>` for `f32`, and
`Mul<f32>` for `Dir2`.
2024-03-03 17:44:16 +00:00
Joona Aalto
f418de8eb6
Rename Direction2d/3d to Dir2/3 (#12189)
# Objective

Split up from #12017, rename Bevy's direction types.

Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.

However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.

This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.

Some examples of what it looks like: (copied from #12017)

```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);

// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```

```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
    Vec3::ZERO,
    Direction3d::X,
    f32::MAX,
    true,
    SpatialQueryFilter::default(),
);

// After
let hit = spatial_query.cast_ray(
    Vec3::ZERO,
    Dir3::X,
    f32::MAX,
    true,
    SpatialQueryFilter::default(),
);
```

```rust
// Before
self.circle(
    Vec3::new(0.0, -2.0, 0.0),
    Direction3d::Y,
    5.0,
    Color::TURQUOISE,
);

// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```

## Solution

Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.

---

## Migration Guide

The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.

## Additional Context

This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.

---------

Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
JohnTheCoolingFan
a543536a34
Cubic splines overhaul (#10701)
# Objective

Improve the `bevy::math::cubic_splines` module by making it more
flexible and adding new curve types.
Closes #10220 

## Solution

Added new spline types and improved existing

---

## Changelog

### Added

- `CubicNurbs` rational cubic curve generator, allows setting the knot
vector and weights associated with every point
- `LinearSpline` curve generator, allows generating a linearly
interpolated curve segment
- Ability to push additional cubic segments to `CubicCurve`
- `IntoIterator` and `Extend` implementations for `CubicCurve`

### Changed

- `Point` trait has been implemented for more types: `Quat` and `Vec4`.
- `CubicCurve::coefficients` was moved to `CubicSegment::coefficients`
because the function returns `CubicSegment`, so it seems logical to be
associated with `CubicSegment` instead. The method is still not public.

### Fixed

- `CubicBSpline::new` was referencing Cardinal spline instead of
B-Spline

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
Co-authored-by: Miles Silberling-Cook <nth.tensor@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-02-28 17:18:42 +00:00
Joona Aalto
9bd6cc0a5e
Add Direction3dA and move direction types out of primitives (#12018)
# Objective

Split up from #12017, add an aligned version of `Direction3d` for SIMD,
and move direction types out of `primitives`.

## Solution

Add `Direction3dA` and move direction types into a new `direction`
module.

---

## Migration Guide

The `Direction2d`, `Direction3d`, and `InvalidDirectionError` types have
been moved out of `bevy::math::primitives`.

Before:

```rust
use bevy::math::primitives::Direction3d;
```

After:

```rust
use bevy::math::Direction3d;
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-02-26 13:57:49 +00:00
github-actions[bot]
e7c3359c4b
Bump Version after Release (#12020)
Fixes #12016.

Bump version after release
This PR has been auto-generated

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François <mockersf@gmail.com>
2024-02-21 20:58:59 +00:00
Aztro
eef7dbefe8
Add single-f32 constructors for a few (very few) primitives (#11934)
# Objective

- I hated having to do `Cuboid::new(1.0, 1.0, 1.0)` or
`Cuboid::from_size(Vec3::splat(1.0))` when there should be a much easier
way to do this.

## Solution

- Implemented a `from_length()` method that only takes in a single
float, and constructs a primitive of equal size in all directions.
- Ex:
  ```rs
  // These:
  Cuboid::new(1.0, 1.0, 1.0);
  Cuboid::from_size(Vec3::splat(1.0));
  // Are equivalent to this:
  Cuboid::from_length(1.0);
  ```
 - For the rest of the changed primitives:
    ```rs
    Rectangle::from_length(1.0);
    Plane3d::default().mesh().from_length(1.0);
    ```
2024-02-18 07:43:45 +00:00
Carter Anderson
abb8c353f4
Release 0.13.0 (#11920)
Bump Bevy crates to 0.13.0 in preparation for release.

(Note that we accidentally skipped the `0.13.0-dev` step this cycle)
2024-02-17 09:24:25 +00:00
Joona Aalto
cf15e6bba3
Implement Meshable for some 3D primitives (#11688)
# Objective

Split up from #11007, fixing most of the remaining work for #10569.

Implement `Meshable` for `Cuboid`, `Sphere`, `Cylinder`, `Capsule`,
`Torus`, and `Plane3d`. This covers all shapes that Bevy has mesh
structs for in `bevy_render::mesh::shapes`.

`Cone` and `ConicalFrustum` are new shapes, so I can add them in a
follow-up, or I could just add them here directly if that's preferrable.

## Solution

Implement `Meshable` for `Cuboid`, `Sphere`, `Cylinder`, `Capsule`,
`Torus`, and `Plane3d`.

The logic is mostly just a copy of the the existing `bevy_render`
shapes, but `Plane3d` has a configurable surface normal that affects the
orientation. Some property names have also been changed to be more
consistent.

The default values differ from the old shapes to make them a bit more
logical:

- Spheres now have a radius of 0.5 instead of 1.0. The default capsule
is equivalent to the default cylinder with the sphere's halves glued on.
- The inner and outer radius of the torus are now 0.5 and 1.0 instead of
0.5 and 1.5 (i.e. the new minor and major radii are 0.25 and 0.75). It's
double the width of the default cuboid, half of its height, and the
default sphere matches the size of the hole.
- `Cuboid` is 1x1x1 by default unlike the dreaded `Box` which is 2x1x1.

Before, with "old" shapes:


![old](https://github.com/bevyengine/bevy/assets/57632562/733f3dda-258c-4491-8152-9829e056a1a3)

Now, with primitive meshing:


![new](https://github.com/bevyengine/bevy/assets/57632562/5a1af14f-bb98-401d-82cf-de8072fea4ec)

I only changed the `3d_shapes` example to use primitives for now. I can
change them all in this PR or a follow-up though, whichever way is
preferrable.

### Sphere API

Spheres have had separate `Icosphere` and `UVSphere` structs, but with
primitives we only have one `Sphere`.

We need to handle this with builders:

```rust
// Existing structs
let ico = Mesh::try_from(Icophere::default()).unwrap();
let uv = Mesh::from(UVSphere::default());

// Primitives
let ico = Sphere::default().mesh().ico(5).unwrap();
let uv = Sphere::default().mesh().uv(32, 18);
```

We could add methods on `Sphere` directly to skip calling `.mesh()`.

I also added a `SphereKind` enum that can be used with the `kind`
method:

```rust
let ico = Sphere::default()
    .mesh()
    .kind(SphereKind::Ico { subdivisions: 8 })
    .build();
```

The default mesh for a `Sphere` is an icosphere with 5 subdivisions
(like the default `Icosphere`).

---

## Changelog

- Implement `Meshable` and `Default` for `Cuboid`, `Sphere`, `Cylinder`,
`Capsule`, `Torus`, and `Plane3d`
- Use primitives in `3d_shapes` example

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-02-06 21:44:13 +00:00
Tristan Guichaoua
694c06f3d0
Inverse missing_docs logic (#11676)
# Objective

Currently the `missing_docs` lint is allowed-by-default and enabled at
crate level when their documentations is complete (see #3492).
This PR proposes to inverse this logic by making `missing_docs`
warn-by-default and mark crates with imcomplete docs allowed.

## Solution

Makes `missing_docs` warn at workspace level and allowed at crate level
when the docs is imcomplete.
2024-02-03 21:40:55 +00:00
Joona Aalto
9bad607df9
Implement meshing for Capsule2d (#11639)
# Objective

The `Capsule2d` primitive was added in #11585. It should support meshing
like the other 2D primitives.

## Solution

Implement meshing for `Capsule2d`.

It doesn't currently support "rings" like Bevy's `Capsule` shape (not
`Capsule3d`), but it does support resolution to control the number of
vertices used for one hemicircle. The total vertex count is two times
the resolution; if we allowed setting the full vertex count, odd numbers
would lead to uneven vertex counts for the top and bottom hemicircles
and produce potentially unwanted results.

The capsule looks like this (with UV visualization and wireframe) using
resolutions of 16, 8, and 3:

![Resolution
16](https://github.com/bevyengine/bevy/assets/57632562/feae22de-bdc5-438a-861f-848284b67a52)
![Resolution
8](https://github.com/bevyengine/bevy/assets/57632562/e95aab8e-793f-45ac-8a74-8be39f7626dd)
![Resolution of
3](https://github.com/bevyengine/bevy/assets/57632562/bcf01d23-1d8b-4cdb-966a-c9022a07c287)

The `2d_shapes` example now includes the capsule, so we also get one
more color of the rainbow 🌈

![New 2D shapes
example](https://github.com/bevyengine/bevy/assets/57632562/1c45b5f5-d26a-4e8c-8e8a-e106ab14d46e)
2024-02-03 18:03:43 +00:00
Robert Walter
041731b7e0
Drawing Primitives with Gizmos (#11072)
The PR is in a reviewable state now in the sense that the basic
implementations are there. There are still some ToDos that I'm aware of:

- [x] docs for all the new structs and traits
- [x] implement `Default` and derive other useful traits for the new
structs
- [x] Take a look at the notes again (Do this after a first round of
reviews)
- [x] Take care of the repetition in the circle drawing functions

---

# Objective

- TLDR: This PR enables us to quickly draw all the newly added
primitives from `bevy_math` in immediate mode with gizmos
- Addresses #10571

## Solution

- This implements the first design idea I had that covered everything
that was mentioned in the Issue
https://github.com/bevyengine/bevy/issues/10571#issuecomment-1863646197

--- 

## Caveats

- I added the `Primitive(2/3)d` impls for `Direction(2/3)d` to make them
work with the current solution. We could impose less strict requirements
for the gizmoable objects and remove the impls afterwards if the
community doesn't like the current approach.

---

## Changelog

- implement capabilities to draw ellipses on the gizmo in general (this
was required to have some code which is able to draw the ellipse
primitive)
- refactored circle drawing code to use the more general ellipse drawing
code to keep code duplication low
- implement `Primitive2d` for `Direction2d` and impl `Primitive3d` for
`Direction3d`
- implement trait to draw primitives with specialized details with
gizmos
  - `GizmoPrimitive2d` for all the 2D primitives
  - `GizmoPrimitive3d` for all the 3D primitives
- (question while writing this: Does it actually matter if we split this
in 2D and 3D? I guess it could be useful in the future if we do
something based on the main rendering mode even though atm it's kinda
useless)

---

---------

Co-authored-by: nothendev <borodinov.ilya@gmail.com>
2024-02-02 21:13:03 +00:00
Rose Hudson
d6f1649646
return Direction3d from Transform::up and friends (#11604)
# Objective
Drawing a `Gizmos::circle` whose normal is derived from a Transform's
local axes now requires converting a Vec3 to a Direction3d and
unwrapping the result, and I think we shold move the conversion into
Bevy.

## Solution
We can make
`Transform::{left,right,up,down,forward,back,local_x,local_y,local_z}`
return a Direction3d, because they know that their results will be of
finite non-zero length (roughly 1.0).

---

## Changelog
`Transform::up()` and similar functions now return `Direction3d` instead
of `Vec3`.

## Migration Guide
Callers of `Transform::up()` and similar functions may have to
dereference the returned `Direction3d` to get to the inner `Vec3`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-02-02 15:05:35 +00:00
NiseVoid
0ffc8d8a6f
Rename RayTest to RayCast (#11635)
# Objective

- `RayTest` vs `AabbCast` and `CircleCast` is inconsistent

## Solution

- Renaming the other two would only make the name more confusing, so we
rename `RayTest2d/3d` to `RayCast2d/3d`
2024-02-02 15:01:04 +00:00
Joona Aalto
6f2eec8f78
Support rotating Direction3d by Quat (#11649)
# Objective

It's often necessary to rotate directions, but it currently has to be
done like this:

```rust
Direction3d::new_unchecked(quat * *direction)
```

It'd be nice if you could rotate `Direction3d` directly:

```rust
quat * direction
```

## Solution

Implement `Mul<Direction3d>` for `Quat` ~~and the other way around.~~
(Glam doesn't impl `Mul<Quat>` or `MulAssign<Quat>` for `Vec3`)

The quaternion must be a unit quaternion to keep the direction
normalized, so there is a `debug_assert!` to be sure. Almost all `Quat`
constructors produce unit quaternions, so there should only be issues if
doing something like `quat + quat` instead of `quat * quat`, using
`Quat::from_xyzw` directly, or when you have significant enough drift
caused by e.g. physics simulation that doesn't normalize rotation. In
general, these would probably cause unexpected results anyway.

I also moved tests around slightly to make `dim2` and `dim3` more
consistent (`dim3` had *two* separate `test` modules for some reason).

In the future, we'll probably want a `Rotation2d` type that would
support the same for `Direction2d`. I considered implementing
`Mul<Mat2>` for `Direction2d`, but that would probably be more
questionable since `Mat2` isn't as clearly associated with rotations as
`Quat` is.
2024-02-01 20:08:24 +00:00
Joona Aalto
d30fdda2c3
Implement approx traits for direction types (#11650)
# Objective

`approx` has traits like
[`AbsDiffEq`](https://docs.rs/approx/latest/approx/trait.AbsDiffEq.html),
[`RelativeEq`](https://docs.rs/approx/latest/approx/trait.RelativeEq.html),
and [`UlpsEq`](https://docs.rs/approx/latest/approx/trait.UlpsEq.html).
Glam implements them for its math types when the `approx` feature is
enabled. Bevy's `Direction2d` and `Direction3d` should implement these
too.

## Solution

Implement the traits. See [how Glam implements them for its own math
types](https://github.com/bitshifter/glam-rs/blob/main/src/features/impl_approx.rs).
For the epsilon values, I use the same as `Vec2`/`Vec3` (just
`f32::EPSILON`).
2024-02-01 19:22:28 +00:00
NiseVoid
e3126a494f
Add Clone to intersection test types (#11640)
# Objective

- Add Clone to RayTest/AabbCast2d/AabbCast3d/CircleCast/SphereCast
2024-02-01 00:54:30 +00:00
NiseVoid
1b98de68fe
Add volume cast intersection tests (#11586)
# 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
2024-01-31 20:14:15 +00:00
Joona Aalto
a9f061e909
Add Capsule2d primitive (#11585)
# Objective

Currently, the `Capsule` primitive is technically dimension-agnostic in
that it implements both `Primitive2d` and `Primitive3d`. This seems good
on paper, but it can often be useful to have separate 2D and 3D versions
of primitives.

For example, one might want a two-dimensional capsule mesh. We can't
really implement both 2D and 3D meshing for the same type using the
upcoming `Meshable` trait (see #11431). We also currently don't
implement `Bounded2d` for `Capsule`, see
https://github.com/bevyengine/bevy/pull/11336#issuecomment-1890797788.

Having 2D and 3D separate at a type level is more explicit, and also
more consistent with the existing primitives, as there are no other
types that implement both `Primitive2d` and `Primitive3d` at the same
time.

## Solution

Rename `Capsule` to `Capsule3d` and add `Capsule2d`. `Capsule2d`
implements `Bounded2d`.

For now, I went for `Capsule2d` for the sake of consistency and clarity.
Mathematically the more accurate term would be `Stadium` or `Pill` (see
[Wikipedia](https://en.wikipedia.org/wiki/Stadium_(geometry))), but
those might be less obvious to game devs. For reference, Godot has
[`CapsuleShape2D`](https://docs.godotengine.org/en/stable/classes/class_capsuleshape2d.html).
I can rename it if others think the geometrically correct name is better
though.

---

## Changelog

- Renamed `Capsule` to `Capsule3d`
- Added `Capsule2d` with `Bounded2d` implemented

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-29 17:52:04 +00:00
Joona Aalto
2bf481c03b
Add Meshable trait and implement meshing for 2D primitives (#11431)
# Objective

The first part of #10569, split up from #11007.

The goal is to implement meshing support for Bevy's new geometric
primitives, starting with 2D primitives. 3D meshing will be added in a
follow-up, and we can consider removing the old mesh shapes completely.

## Solution

Add a `Meshable` trait that primitives need to implement to support
meshing, as suggested by the
[RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/12-primitive-shapes.md#meshing).

```rust
/// A trait for shapes that can be turned into a [`Mesh`].
pub trait Meshable {
    /// The output of [`Self::mesh`]. This can either be a [`Mesh`]
    /// or a builder used for creating a [`Mesh`].
    type Output;

    /// Creates a [`Mesh`] for a shape.
    fn mesh(&self) -> Self::Output;
}
```

This PR implements it for the following primitives:

- `Circle`
- `Ellipse`
- `Rectangle`
- `RegularPolygon`
- `Triangle2d`

The `mesh` method typically returns a builder-like struct such as
`CircleMeshBuilder`. This is needed to support shape-specific
configuration for things like mesh resolution or UV configuration:

```rust
meshes.add(Circle { radius: 0.5 }.mesh().resolution(64));
```

Note that if no configuration is needed, you can even skip calling
`mesh` because `From<MyPrimitive>` is implemented for `Mesh`:

```rust
meshes.add(Circle { radius: 0.5 });
```

I also updated the `2d_shapes` example to use primitives, and tweaked
the colors to have better contrast against the dark background.

Before:

![Old 2D
shapes](https://github.com/bevyengine/bevy/assets/57632562/f1d8c2d5-55be-495f-8ed4-5890154b81ca)

After:

![New 2D
shapes](https://github.com/bevyengine/bevy/assets/57632562/f166c013-34b8-4752-800a-5517b284d978)

Here you can see the UVs and different facing directions: (taken from
#11007, so excuse the 3D primitives at the bottom left)

![UVs and facing
directions](https://github.com/bevyengine/bevy/assets/57632562/eaf0be4e-187d-4b6d-8fb8-c996ba295a8a)

---

## Changelog

- Added `bevy_render::mesh::primitives` module
- Added `Meshable` trait and implemented it for:
  - `Circle`
  - `Ellipse`
  - `Rectangle`
  - `RegularPolygon`
  - `Triangle2d`
- Implemented `Default` and `Copy` for several 2D primitives
- Updated `2d_shapes` example to use primitives
- Tweaked colors in `2d_shapes` example to have better contrast against
the (new-ish) dark background

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-29 16:47:47 +00:00
Joona Aalto
92567490a9
Add more constructors and math helpers for primitive shapes (#10632)
# Objective

Working towards finishing a part of #10572, this PR adds a ton of math
helpers and useful constructors for primitive shapes. I also tried
fixing some naming inconsistencies.

## Solution

- Add mathematical helpers like `area`, `volume`, `perimeter`,
`RegularPolygon::inradius` and so on, trying to cover all core
mathematical properties of each shape
- Add some constructors like `Rectangle::from_corners`,
`Cuboid::from_corners` and `Plane3d::from_points`

I also derived `PartialEq` for the shapes where it's trivial. Primitives
like `Line2d` and `Segment2d` are not trivial because you could argue
that they would be equal if they had an opposite direction.

All mathematical methods have tests with reference values computed by
hand or with external tools.

## Todo

- [x] Add tests to verify that the values from mathematical helpers are
correct

---------

Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-01-29 16:04:51 +00:00
NiseVoid
8851532890
Add RayTest2d and RayTest3d (#11310)
# Objective

Implement a raycast intersection test for bounding volumes

## Solution

- Implement RayTest2d and RayTest3d types

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-01-28 20:12:08 +00:00
NiseVoid
755917fe4b
Derive PartialEq, Serialize, Deserialize and Reflect on primitives (#11514)
# Objective

- Implement common traits on primitives

## Solution

- Derive PartialEq on types that were missing it.
- Derive Copy on small types that were missing it.
- Derive Serialize/Deserialize if the feature on bevy_math is enabled.
- Add a lot of cursed stuff to the bevy_reflect `impls` module.
2024-01-28 14:55:30 +00:00
Joona Aalto
dd4d07dc9c
Add new constructors for Circle and Sphere (#11526)
# Objective

Make APIs more consistent and ergonomic by adding a `new` constructor
for `Circle` and `Sphere`.

This could be seen as a redundant "trivial constructor", but in
practise, it seems valuable to me. I have lots of cases where formatting
becomes ugly because of the lack of a constructor, like this:

```rust
Circle {
    radius: self.radius(),
}
.contains_local_point(centered_pt)
```

With `new`, it'd be formatted much nicer:

```rust
Circle::new(self.radius()).contains_local_point(centered_pt)
```

Of course, this is just one example, but my circle/sphere definitions
very frequently span three or more lines when they could fit on one.

Adding `new` also increases consistency. `Ellipse` has `new` already,
and so does the mesh version of `Circle`.

## Solution

Add a `new` constructor for `Circle` and `Sphere`.
2024-01-26 16:00:59 +00:00
Joona Aalto
6a3b059db9
Implement bounding volume intersections (#11439)
# 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>
2024-01-22 17:55:59 +00:00
Doonv
0387331c12
Direction: Rename from_normalized to new_unchecked (#11425)
# Objective

`Direction2d::from_normalized` & `Direction3d::from_normalized` don't
emphasize that importance of the vector being normalized enough.

## Solution

Rename `from_normalized` to `new_unchecked` and add more documentation.

---

`Direction2d` and `Direction3d` were added somewhat recently in
https://github.com/bevyengine/bevy/pull/10466 (after 0.12), so I don't
think documenting the changelog and migration guide is necessary (Since
there is no major previous version to migrate from).

But here it is anyway in case it's needed:

## Changelog

- Renamed `Direction2d::from_normalized` and
`Direction3d::from_normalized` to `new_unchecked`.

## Migration Guide

- Renamed `Direction2d::from_normalized` and
`Direction3d::from_normalized` to `new_unchecked`.

---------

Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-01-20 21:52:09 +00:00
Joona Aalto
c6f45831e9
Add geometric primitives to bevy_math::prelude (#11432)
# Objective

Currently, the `primitives` module is inside of the prelude for
`bevy_math`, but the actual primitives are not. This requires either
importing the shapes everywhere that uses them, or adding the
`primitives::` prefix:

```rust
let rectangle = meshes.add(primitives::Rectangle::new(5.0, 2.5));
```

(Note: meshing isn't actually implemented yet, but it's in #11431)

The primitives are meant to be used for a variety of tasks across
several crates, like for meshing, bounding volumes, gizmos, colliders,
and so on, so I think having them in the prelude is justified. It would
make several common tasks a lot more ergonomic.

```rust
let rectangle = meshes.add(Rectangle::new(5.0, 2.5));
```

## Solution

Add `primitives::*` to `bevy_math::prelude`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-20 20:15:38 +00:00
Joona Aalto
c31f3aa128
Add Aabb2d::new and Aabb3d::new constructors (#11433)
# 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.
2024-01-20 20:12:20 +00:00
Joona Aalto
b592a72916
Change Ellipse representation and improve helpers (#11435)
# Objective

Currently, the `Ellipse` primitive is represented by a `half_width` and
`half_height`. To improve consistency (similarly to #11434), it might
make more sense to use a `Vec2` `half_size` instead.

Alternatively, to make the elliptical nature clearer, the properties
could also be called `radius_x` and `radius_y`.

Secondly, `Ellipse::new` currently takes a *full* width and height
instead of two radii. I would expect it to take the half-width and
half-height because ellipses and circles are almost always defined using
radii. I wouldn't expect `Circle::new` to take a diameter (if we had
that method).

## Solution

Change `Ellipse` to store a `half_size` and `new` to take the half-width
and half-height.

I also added a `from_size` method similar to `Rectangle::from_size`, and
added the `semi_minor` and `semi_major` helpers to get the
semi-minor/major radius.
2024-01-20 18:04:53 +00:00
Joona Aalto
6337fb33ff
Improve Rectangle and Cuboid consistency (#11434)
# Objective

The `Rectangle` and `Cuboid` primitives currently use different
representations:

```rust
pub struct Rectangle {
    /// The half width of the rectangle
    pub half_width: f32,
    /// The half height of the rectangle
    pub half_height: f32,
}

pub struct Cuboid {
    /// Half of the width, height and depth of the cuboid
    pub half_extents: Vec3,
}
```

The property names and helpers are also inconsistent. `Cuboid` has
`half_extents`, but it also has a method called `from_size`. Most
existing code also uses "size" instead of "extents".

## Solution

Represent both `Rectangle` and `Cuboid` with `half_size` properties.
2024-01-20 18:03:47 +00:00
Joona Aalto
c62ad4b2c4
Implement bounding volumes for primitive shapes (#11336)
# 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-a2b3ee16f8b4


https://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.
2024-01-18 15:55:36 +00:00
BD103
6f6269e195
Remove Default impl for CubicCurve (#11335)
# Objective

- Implementing `Default` for
[`CubicCurve`](https://docs.rs/bevy/latest/bevy/math/cubic_splines/struct.CubicCurve.html)
does not make sense because it cannot be mutated after creation.
- Closes #11209.
- Alternative to #11211.

## Solution

- Remove `Default` from `CubicCurve`'s derive statement.

Based off of @mockersf comment
(https://github.com/bevyengine/bevy/pull/11211#issuecomment-1880088036):

> CubicCurve can't be updated once created... I would prefer to remove
the Default impl as it doesn't make sense

---

## Changelog

- Removed the `Default` implementation for `CubicCurve`.

## Migration Guide

- Remove `CubicCurve` from any structs that implement `Default`.
- Wrap `CubicCurve` in a new type and provide your own default.

```rust
#[derive(Deref)]
struct MyCubicCurve<P: Point>(pub CubicCurve<P>);

impl Default for MyCubicCurve<Vec2> {
    fn default() -> Self {
        let points = [[
            vec2(-1.0, -20.0),
            vec2(3.0, 2.0),
            vec2(5.0, 3.0),
            vec2(9.0, 8.0),
        ]];

        Self(CubicBezier::new(points).to_curve())
    }
}
```
2024-01-14 04:40:37 +00:00
NiseVoid
c4e479a2d4
Implement bounding volume types (#10946)
# Objective

Implement bounding volume trait and the 4 types from
https://github.com/bevyengine/bevy/issues/10570. I will add intersection
tests in a future PR.

## Solution

Implement mostly everything as written in the issue, except:
- Intersection is no longer a method on the bounding volumes, but a
separate trait.
- I implemented a `visible_area` since it's the most common usecase to
care about the surface that could collide with cast rays.
  - Maybe we want both?

---

## Changelog

- Added bounding volume types to bevy_math

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-10 23:18:51 +00:00
irate
ec14e946b8
Update glam, encase and hexasphere (#11082)
Update to `glam` 0.25, `encase` 0.7 and `hexasphere` to 10.0

## Changelog
Added the `FloatExt` trait to the `bevy_math` prelude which adds `lerp`,
`inverse_lerp` and `remap` methods to the `f32` and `f64` types.
2024-01-08 22:58:45 +00:00
Joona Aalto
bcbb7bb9dd
Add new_and_length method to Direction2d and Direction3d (#11172)
# Objective

When creating a normalized direction from a vector, it can be useful to
get both the direction *and* the original length of the vector.

This came up when I was recreating some Parry APIs using bevy_math, and
doing it manually is quite painful. Nalgebra calls this method
[`Unit::try_new_and_get`](https://docs.rs/nalgebra/latest/nalgebra/base/struct.Unit.html#method.try_new_and_get).

## Solution

Add a `new_and_length` method to `Direction2d` and `Direction3d`.

Usage:

```rust
if let Ok((direction, length)) = Direction2d::new_and_length(Vec2::X * 10.0) {
    assert_eq!(direction, Vec2::X);
    assert_eq!(length, 10.0);
}
```

I'm open to different names, couldn't come up with a perfectly clear one
that isn't too long. My reasoning with the current name is that it's
like using `new` and calling `length` on the original vector.
2024-01-08 22:36:56 +00:00
Joona Aalto
0349809420
Add libm feature to bevy_math (#11238)
# Objective

Different platforms use their own implementations of several
mathematical functions (especially transcendental functions like sin,
cos, tan, atan, and so on) to provide hardware-level optimization using
intrinsics. This is good for performance, but bad when you expect
consistent outputs across machines.

[`libm`](https://github.com/rust-lang/libm) is a widely used crate that
provides mathematical functions that don't use intrinsics like `std`
functions. This allows bit-for-bit deterministic math across hardware,
which is crucial for things like cross-platform deterministic physics
simulation.

Glam has the `libm` feature for using [`libm` for the
math](d2871a151b/src/f32/math.rs (L35))
in its own types. This would be nice to expose as a feature in
`bevy_math`.

## Solution

Add `libm` feature to `bevy_math`. We could name it something like
`enhanced-determinism`, but this wouldn't be accurate for the rest of
Bevy, so I think just `libm` is more fitting and explicit.
2024-01-06 22:01:57 +00:00
Joona Aalto
536a7bd810
Add approx feature to bevy_math (#11176)
# Objective

`bevy_math` re-exports Glam, but doesn't have a feature for enabling
`approx` for it. Many projects (including some of Bevy's own crates)
need `approx`, and it'd be nice if you didn't have to manually add Glam
to specify the feature for it.

## Solution

Add an `approx` feature to `bevy_math`.
2024-01-02 18:10:44 +00:00
Joona Aalto
2c5439b25e
Add constants for Direction2d and Direction3d (#11180)
# Objective

I often need a direction along one of the cartesian XYZ axes, and it
currently requires e.g. `Direction2d::from_normalized(Vec2::X)`, which
isn't ideal.

## Solution

Add direction constants that are the same as the ones on Glam types. I
also copied the doc comment format "A unit vector pointing along the ...
axis", but I can change it if there's a better wording for directions.
2024-01-02 17:00:23 +00:00
Joona Aalto
6086d4193e
Implement Neg for Direction2d and Direction3d (#11179)
# Objective

I frequently encounter cases where I need to get the opposite direction.
This currently requires something like
`Direction2d::from_normalized(-*direction)`, which is very inconvenient.

## Solution

Implement `Neg` for `Direction2d` and `Direction3d`.
2024-01-02 16:46:03 +00:00
Doonv
189ceaf0d3
Replace or document ignored doctests (#11040)
# Objective

There are a lot of doctests that are `ignore`d for no documented reason.
And that should be fixed.

## Solution

I searched the bevy repo with the regex ` ```[a-z,]*ignore ` in order to
find all `ignore`d doctests. For each one of the `ignore`d doctests, I
did the following steps:
1. Attempt to remove the `ignored` attribute while still passing the
test. I did this by adding hidden dummy structs and imports.
2. If step 1 doesn't work, attempt to replace the `ignored` attribute
with the `no_run` attribute while still passing the test.
3. If step 2 doesn't work, keep the `ignored` attribute but add
documentation for why the `ignored` attribute was added.

---------

Co-authored-by: François <mockersf@gmail.com>
2024-01-01 16:50:56 +00:00
Olle Lukowski
6b9cd57956
Introduce AspectRatio struct (#10368)
# Objective

- Fix an inconsistency in the calculation of aspect ratio's. 
- Fixes #10288 

## Solution

- Created an intermediate `AspectRatio` struct, as suggested in the
issue. This is currently just used in any places where aspect ratio
calculations happen, to prevent doing it wrong. In my and @mamekoro 's
opinion, it would be better if this was used instead of a normal `f32`
in various places, but I didn't want to make too many changes to begin
with.

## Migration Guide
- Anywhere where you are currently expecting a f32 when getting aspect
ratios, you will now receive a `AspectRatio` struct. this still holds
the same value.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-12-17 02:01:26 +00:00
Tygyh
645625b789
Replace deprecated elements (#10999)
# Objective

- Replace deprecated elements.

## Solution

- Remove 'std::' from constants.
2023-12-16 23:24:49 +00:00
Joona Aalto
029dd06f7d
Add Direction2d::from_xy and Direction3d::from_xyz (#10882)
# Objective

Make direction construction a bit more ergonomic.

## Solution

Add `Direction2d::from_xy` and `Direction3d::from_xyz`, similar to
`Transform::from_xyz`:

```rust
let dir2 = Direction2d::from_xy(0.5, 0.5).unwrap();
let dir3 = Direction3d::from_xyz(0.5, 0.5, 0.5).unwrap();
```

This can be a bit cleaner than using `new`:

```rust
let dir2 = Direction2d::new(Vec2::new(0.5, 0.5)).unwrap();
let dir3 = Direction3d::new(Vec3::new(0.5, 0.5, 0.5)).unwrap();
```
2023-12-14 14:56:07 +00:00
Joona Aalto
d9aac887b5
Split Ray into Ray2d and Ray3d and simplify plane construction (#10856)
# Objective

A better alternative version of #10843.

Currently, Bevy has a single `Ray` struct for 3D. To allow better
interoperability with Bevy's primitive shapes (#10572) and some third
party crates (that handle e.g. spatial queries), it would be very useful
to have separate versions for 2D and 3D respectively.

## Solution

Separate `Ray` into `Ray2d` and `Ray3d`. These new structs also take
advantage of the new primitives by using `Direction2d`/`Direction3d` for
the direction:

```rust
pub struct Ray2d {
    pub origin: Vec2,
    pub direction: Direction2d,
}

pub struct Ray3d {
    pub origin: Vec3,
    pub direction: Direction3d,
}
```

and by using `Plane2d`/`Plane3d` in `intersect_plane`:

```rust
impl Ray2d {
    // ...
    pub fn intersect_plane(&self, plane_origin: Vec2, plane: Plane2d) -> Option<f32> {
        // ...
    }
}
```

---

## Changelog

### Added

- `Ray2d` and `Ray3d`
- `Ray2d::new` and `Ray3d::new` constructors
- `Plane2d::new` and `Plane3d::new` constructors

### Removed

- Removed `Ray` in favor of `Ray3d`

### Changed

- `direction` is now a `Direction2d`/`Direction3d` instead of a vector,
which provides guaranteed normalization
- `intersect_plane` now takes a `Plane2d`/`Plane3d` instead of just a
vector for the plane normal
- `Direction2d` and `Direction3d` now derive `Serialize` and
`Deserialize` to preserve ray (de)serialization

## Migration Guide

`Ray` has been renamed to `Ray3d`.

### Ray creation

Before:

```rust
Ray {
    origin: Vec3::ZERO,
    direction: Vec3::new(0.5, 0.6, 0.2).normalize(),
}
```

After:

```rust
// Option 1:
Ray3d {
    origin: Vec3::ZERO,
    direction: Direction3d::new(Vec3::new(0.5, 0.6, 0.2)).unwrap(),
}

// Option 2:
Ray3d::new(Vec3::ZERO, Vec3::new(0.5, 0.6, 0.2))
```

### Plane intersections

Before:

```rust
let result = ray.intersect_plane(Vec2::X, Vec2::Y);
```

After:

```rust
let result = ray.intersect_plane(Vec2::X, Plane2d::new(Vec2::Y));
```
2023-12-06 14:09:04 +00:00
Joona Aalto
f683b802f1
Impl TryFrom vector for directions and add InvalidDirectionError (#10884)
# Objective

Implement `TryFrom<Vec2>`/`TryFrom<Vec3>` for direction primitives as
considered in #10857.

## Solution

Implement `TryFrom` for the direction primitives.

These are all equivalent:

```rust
let dir2d = Direction2d::try_from(Vec2::new(0.5, 0.5)).unwrap();
let dir2d = Vec2::new(0.5, 0.5).try_into().unwrap(); // (assumes that the type is inferred)
let dir2d = Direction2d::new(Vec2::new(0.5, 0.5)).unwrap();
```

For error cases, an `Err(InvalidDirectionError)` is returned. It
contains the type of failure:

```rust
/// An error indicating that a direction is invalid.
#[derive(Debug, PartialEq)]
pub enum InvalidDirectionError {
    /// The length of the direction vector is zero or very close to zero.
    Zero,
    /// The length of the direction vector is `std::f32::INFINITY`.
    Infinite,
    /// The length of the direction vector is `NaN`.
    NaN,
}
```
2023-12-06 00:05:37 +00:00
irate
83ee6de1da
Remove From implementations from the direction types (#10857)
This removes the `From<Vec2/3>` implementations for the direction types.
It doesn't seem right to have when it only works if the vector is
nonzero and finite and produces NaN otherwise.

Added `Direction2d/3d::new` which uses `Vec2/3::try_normalize` to
guarantee it returns either a valid direction or `None`.

This should make it impossible to create an invalid direction, which I
think was the intention with these types.
2023-12-05 02:44:27 +00:00
Joona Aalto
897b13bf9d
Use minor and major radii for Torus primitive shape (#10643)
# Objective

First, some terminology:

- **Minor radius**: The radius of the tube of a torus, i.e. the
"half-thickness"
- **Major radius**: The distance from the center of the tube to the
center of the torus
- **Inner radius**: The radius of the hole (if it exists), `major_radius
- minor_radius`
- **Outer radius**: The radius of the overall shape, `major_radius +
minor_radius`
- **Ring torus**: The familiar donut shape with a hole in the center,
`major_radius > minor_radius`
- **Horn torus**: A torus that doesn't have a hole but also isn't
self-intersecting, `major_radius == minor_radius`
- **Spindle torus**: A self-intersecting torus, `major_radius <
minor_radius`

Different tori from [Wikipedia](https://en.wikipedia.org/wiki/Torus),
where *R* is the major radius and *r* is the minor radius:


![kuva](https://github.com/bevyengine/bevy/assets/57632562/53ead786-2402-43a7-ae8a-5720e6e54dcc)

Currently, Bevy's torus is represented by a `radius` and `ring_radius`.
I believe these correspond to the outer radius and minor radius, but
they are rather confusing and inconsistent names, and they make the
assumption that the torus always has a ring.

I also couldn't find any other big engines using this representation;
[Godot](https://docs.godotengine.org/en/stable/classes/class_torusmesh.html)
and [Unity
ProBuilder](https://docs.unity3d.com/Packages/com.unity.probuilder@4.0/manual/Torus.html)
use the inner and outer radii, while
[Unreal](https://docs.unrealengine.com/5.3/en-US/BlueprintAPI/GeometryScript/Primitives/AppendTorus/)
uses the minor and major radii.
[Blender](https://docs.blender.org/manual/en/latest/modeling/meshes/primitives.html#torus)
supports both, but defaults to minor/major.

Bevy's `Torus` primitive should have an efficient, consistent, clear and
flexible representation, and the current `radius` and `ring_radius`
properties are not ideal for that.

## Solution

Change `Torus` to be represented by a `minor_radius` and `major_radius`.

- Mathematically correct and consistent
- Flexible, not restricted to ring tori
- Computations and conversions are efficient
  - `inner_radius = major_radius - minor_radius`
  - `outer_radius = major_radius + minor_radius`
- Mathematical formulae for things like area and volume rely on the
minor and major radii, no conversion needed

Perhaps the primary issue with this representation is that "minor
radius" and "major radius" are rather mathematical, and an inner/outer
radius can be more intuitive in some cases. However, this can be
mitigated with constructors and helpers.
2023-11-21 01:49:35 +00:00
Joona Aalto
e1c8d60f91
Add winding order for Triangle2d (#10620)
# Objective

This PR adds some helpers for `Triangle2d` to work with its winding
order. This could also be extended to polygons (and `Triangle3d` once
it's added).

## Solution

- Add `WindingOrder` enum with `Clockwise`, `Counterclockwise` and
`Invalid` variants
- `Invalid` is for cases where the winding order can not be reliably
computed, i.e. the points lie on a single line and the area is zero
- Add `Triangle2d::winding_order` method that uses a signed surface area
to determine the winding order
- Add `Triangle2d::reverse` method that reverses the winding order by
swapping the second and third vertices

The API looks like this:

```rust
let mut triangle = Triangle2d::new(
    Vec2::new(0.0, 2.0),
    Vec2::new(-0.5, -1.2),
    Vec2::new(-1.0, -1.0),
);
assert_eq!(triangle.winding_order(), WindingOrder::Clockwise);

// Reverse winding order
triangle.reverse();
assert_eq!(triangle.winding_order(), WindingOrder::Counterclockwise);
```

I also added tests to make sure the methods work correctly. For now,
they live in the same file as the primitives.

## Open questions

- Should it be `Counterclockwise` or `CounterClockwise`? The first one
is more correct but perhaps a bit less readable. Counter-clockwise is
also a valid spelling, but it seems to be a lot less common than
counterclockwise.
- Is `WindingOrder::Invalid` a good name? Parry uses
`TriangleOrientation::Degenerate`, but I'm not a huge fan, at least as a
non-native English speaker. Any better suggestions?
- Is `WindingOrder` fine in `bevy_math::primitives`? It's not specific
to a dimension, so I put it there for now.
2023-11-20 09:47:05 +00:00
Ame
951c9bb1a2
Add [lints] table, fix adding #![allow(clippy::type_complexity)] everywhere (#10011)
# Objective

- Fix adding `#![allow(clippy::type_complexity)]` everywhere. like #9796

## Solution

- Use the new [lints] table that will land in 1.74
(https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#lints)
- inherit lint to the workspace, crates and examples.
```
[lints]
workspace = true
```

## Changelog

- Bump rust version to 1.74
- Enable lints table for the workspace
```toml
[workspace.lints.clippy]
type_complexity = "allow"
```
- Allow type complexity for all crates and examples
```toml
[lints]
workspace = true
```

---------

Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com>
2023-11-18 20:58:48 +00:00
Aztro
33cd59fb04
Add and impl Primitives (#10580)
# Add and implement constructors for Primitives

- Adds more Primitive types and adds a constructor for almost all of
them
- Works towards finishing #10572 

## Solution

- Created new primitives
    - Torus
    - Conical Frustum
    - Cone
    - Ellipse
- Implemented constructors (`Primitive::new`) for almost every single
other primitive.

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-11-17 20:10:30 +00:00
NiseVoid
01b9ddd92c
Define a basic set of Primitives (#10466)
# Objective

- Implement a subset of
https://github.com/bevyengine/rfcs/blob/main/rfcs/12-primitive-shapes.md#feature-name-primitive-shapes

## Solution

- Define a very basic set of primitives in bevy_math
- Assume a 0,0,0 origin for most shapes
- Use radius and half extents to avoid unnecessary computational
overhead wherever they get used
- Provide both Boxed and const generics variants for shapes with
variable sizes
- Boxed is useful if a 3rd party crate wants to use something like
enum-dispatch for all supported primitives
- Const generics is useful when just working on a single primitive, as
it causes no allocs

#### Some discrepancies from the RFC:

- Box was changed to Cuboid, because Box is already used for an alloc
type
- Skipped Cone because it's unclear where the origin should be for
different uses
- Skipped Wedge because it's too niche for an initial PR (we also don't
implement Torus, Pyramid or a Death Star (there's an SDF for that!))
- Skipped Frustum because while it would be a useful math type, it's not
really a common primitive
- Skipped Triangle3d and Quad3d because those are just rotated 2D shapes

## Future steps

- Add more primitives
- Add helper methods to make primitives easier to construct (especially
when half extents are involved)
- Add methods to calculate AABBs for primitives (useful for physics, BVH
construction, for the mesh AABBs, etc)
- Add wrappers for common and cheap operations, like extruding 2D shapes
and translating them
- Use the primitives to generate meshes
- Provide signed distance functions and gradients for primitives (maybe)

---

## Changelog

- Added a collection of primitives to the bevy_math crate

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2023-11-15 16:51:03 +00:00
github-actions[bot]
bf30a25efc
Release 0.12 (#10362)
Preparing next release
This PR has been auto-generated

---------

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François <mockersf@gmail.com>
2023-11-04 17:24:23 +00:00
Aevyrie
9d088dd144
Add Cubic prefix to all cubic curve generators (#10299)
# Objective

- Fixes #10258 

## Solution

- Renamed.

---

## Changelog

- Changed: `BSpline` -> `CubicBSpline`
- Changed: `CardinalSpline` -> `CubicCardinalSpline`
- Changed: `Hermite` -> `CubicHermite`

## Migration Guide

- Rename: `BSpline` -> `CubicBSpline`
- Rename: `CardinalSpline` -> `CubicCardinalSpline`
- Rename: `Hermite` -> `CubicHermite`
2023-10-28 21:53:38 +00:00
ickshonpe
c959c1ba58
normalize method for Rect (#10297)
# Objective

`normalize` method that expresses a rectangle relative to a normalized
[0..1] x [0..1] space defined by another rectangle.

Useful for UI and texture atlas calculations etc.

---------

Co-authored-by: Rob Parrett <robparrett@gmail.com>
2023-10-28 19:02:58 +00:00
Ame :]
1e9258910c
re-export debug_glam_assert feature (#10206)
# Objective

- I want to use the `debug_glam_assert` feature with bevy.

## Solution

- Re-export the feature flag

---

## Changelog

- Re-export `debug_glam_assert` feature flag from glam.
2023-10-22 23:01:28 +00:00
Robert Swain
5c884c5a15
Automatic batching/instancing of draw commands (#9685)
# Objective

- Implement the foundations of automatic batching/instancing of draw
commands as the next step from #89
- NOTE: More performance improvements will come when more data is
managed and bound in ways that do not require rebinding such as mesh,
material, and texture data.

## Solution

- The core idea for batching of draw commands is to check whether any of
the information that has to be passed when encoding a draw command
changes between two things that are being drawn according to the sorted
render phase order. These should be things like the pipeline, bind
groups and their dynamic offsets, index/vertex buffers, and so on.
  - The following assumptions have been made:
- Only entities with prepared assets (pipelines, materials, meshes) are
queued to phases
- View bindings are constant across a phase for a given draw function as
phases are per-view
- `batch_and_prepare_render_phase` is the only system that performs this
batching and has sole responsibility for preparing the per-object data.
As such the mesh binding and dynamic offsets are assumed to only vary as
a result of the `batch_and_prepare_render_phase` system, e.g. due to
having to split data across separate uniform bindings within the same
buffer due to the maximum uniform buffer binding size.
- Implement `GpuArrayBuffer` for `Mesh2dUniform` to store Mesh2dUniform
in arrays in GPU buffers rather than each one being at a dynamic offset
in a uniform buffer. This is the same optimisation that was made for 3D
not long ago.
- Change batch size for a range in `PhaseItem`, adding API for getting
or mutating the range. This is more flexible than a size as the length
of the range can be used in place of the size, but the start and end can
be otherwise whatever is needed.
- Add an optional mesh bind group dynamic offset to `PhaseItem`. This
avoids having to do a massive table move just to insert
`GpuArrayBufferIndex` components.

## Benchmarks

All tests have been run on an M1 Max on AC power. `bevymark` and
`many_cubes` were modified to use 1920x1080 with a scale factor of 1. I
run a script that runs a separate Tracy capture process, and then runs
the bevy example with `--features bevy_ci_testing,trace_tracy` and
`CI_TESTING_CONFIG=../benchmark.ron` with the contents of
`../benchmark.ron`:
```rust
(
    exit_after: Some(1500)
)
```
...in order to run each test for 1500 frames.

The recent changes to `many_cubes` and `bevymark` added reproducible
random number generation so that with the same settings, the same rng
will occur. They also added benchmark modes that use a fixed delta time
for animations. Combined this means that the same frames should be
rendered both on main and on the branch.

The graphs compare main (yellow) to this PR (red).

### 3D Mesh `many_cubes --benchmark`

<img width="1411" alt="Screenshot 2023-09-03 at 23 42 10"
src="https://github.com/bevyengine/bevy/assets/302146/2088716a-c918-486c-8129-090b26fd2bc4">
The mesh and material are the same for all instances. This is basically
the best case for the initial batching implementation as it results in 1
draw for the ~11.7k visible meshes. It gives a ~30% reduction in median
frame time.

The 1000th frame is identical using the flip tool:

![flip many_cubes-main-mesh3d many_cubes-batching-mesh3d 67ppd
ldr](https://github.com/bevyengine/bevy/assets/302146/2511f37a-6df8-481a-932f-706ca4de7643)

```
     Mean: 0.000000
     Weighted median: 0.000000
     1st weighted quartile: 0.000000
     3rd weighted quartile: 0.000000
     Min: 0.000000
     Max: 0.000000
     Evaluation time: 0.4615 seconds
```

### 3D Mesh `many_cubes --benchmark --material-texture-count 10`

<img width="1404" alt="Screenshot 2023-09-03 at 23 45 18"
src="https://github.com/bevyengine/bevy/assets/302146/5ee9c447-5bd2-45c6-9706-ac5ff8916daf">
This run uses 10 different materials by varying their textures. The
materials are randomly selected, and there is no sorting by material
bind group for opaque 3D so any batching is 'random'. The PR produces a
~5% reduction in median frame time. If we were to sort the opaque phase
by the material bind group, then this should be a lot faster. This
produces about 10.5k draws for the 11.7k visible entities. This makes
sense as randomly selecting from 10 materials gives a chance that two
adjacent entities randomly select the same material and can be batched.

The 1000th frame is identical in flip:

![flip many_cubes-main-mesh3d-mtc10 many_cubes-batching-mesh3d-mtc10
67ppd
ldr](https://github.com/bevyengine/bevy/assets/302146/2b3a8614-9466-4ed8-b50c-d4aa71615dbb)

```
     Mean: 0.000000
     Weighted median: 0.000000
     1st weighted quartile: 0.000000
     3rd weighted quartile: 0.000000
     Min: 0.000000
     Max: 0.000000
     Evaluation time: 0.4537 seconds
```

### 3D Mesh `many_cubes --benchmark --vary-per-instance`

<img width="1394" alt="Screenshot 2023-09-03 at 23 48 44"
src="https://github.com/bevyengine/bevy/assets/302146/f02a816b-a444-4c18-a96a-63b5436f3b7f">
This run varies the material data per instance by randomly-generating
its colour. This is the worst case for batching and that it performs
about the same as `main` is a good thing as it demonstrates that the
batching has minimal overhead when dealing with ~11k visible mesh
entities.

The 1000th frame is identical according to flip:

![flip many_cubes-main-mesh3d-vpi many_cubes-batching-mesh3d-vpi 67ppd
ldr](https://github.com/bevyengine/bevy/assets/302146/ac5f5c14-9bda-4d1a-8219-7577d4aac68c)

```
     Mean: 0.000000
     Weighted median: 0.000000
     1st weighted quartile: 0.000000
     3rd weighted quartile: 0.000000
     Min: 0.000000
     Max: 0.000000
     Evaluation time: 0.4568 seconds
```

### 2D Mesh `bevymark --benchmark --waves 160 --per-wave 1000 --mode
mesh2d`

<img width="1412" alt="Screenshot 2023-09-03 at 23 59 56"
src="https://github.com/bevyengine/bevy/assets/302146/cb02ae07-237b-4646-ae9f-fda4dafcbad4">
This spawns 160 waves of 1000 quad meshes that are shaded with
ColorMaterial. Each wave has a different material so 160 waves currently
should result in 160 batches. This results in a 50% reduction in median
frame time.

Capturing a screenshot of the 1000th frame main vs PR gives:

![flip bevymark-main-mesh2d bevymark-batching-mesh2d 67ppd
ldr](https://github.com/bevyengine/bevy/assets/302146/80102728-1217-4059-87af-14d05044df40)

```
     Mean: 0.001222
     Weighted median: 0.750432
     1st weighted quartile: 0.453494
     3rd weighted quartile: 0.969758
     Min: 0.000000
     Max: 0.990296
     Evaluation time: 0.4255 seconds
```

So they seem to produce the same results. I also double-checked the
number of draws. `main` does 160000 draws, and the PR does 160, as
expected.

### 2D Mesh `bevymark --benchmark --waves 160 --per-wave 1000 --mode
mesh2d --material-texture-count 10`

<img width="1392" alt="Screenshot 2023-09-04 at 00 09 22"
src="https://github.com/bevyengine/bevy/assets/302146/4358da2e-ce32-4134-82df-3ab74c40849c">
This generates 10 textures and generates materials for each of those and
then selects one material per wave. The median frame time is reduced by
50%. Similar to the plain run above, this produces 160 draws on the PR
and 160000 on `main` and the 1000th frame is identical (ignoring the fps
counter text overlay).

![flip bevymark-main-mesh2d-mtc10 bevymark-batching-mesh2d-mtc10 67ppd
ldr](https://github.com/bevyengine/bevy/assets/302146/ebed2822-dce7-426a-858b-b77dc45b986f)

```
     Mean: 0.002877
     Weighted median: 0.964980
     1st weighted quartile: 0.668871
     3rd weighted quartile: 0.982749
     Min: 0.000000
     Max: 0.992377
     Evaluation time: 0.4301 seconds
```

### 2D Mesh `bevymark --benchmark --waves 160 --per-wave 1000 --mode
mesh2d --vary-per-instance`

<img width="1396" alt="Screenshot 2023-09-04 at 00 13 53"
src="https://github.com/bevyengine/bevy/assets/302146/b2198b18-3439-47ad-919a-cdabe190facb">
This creates unique materials per instance by randomly-generating the
material's colour. This is the worst case for 2D batching. Somehow, this
PR manages a 7% reduction in median frame time. Both main and this PR
issue 160000 draws.

The 1000th frame is the same:

![flip bevymark-main-mesh2d-vpi bevymark-batching-mesh2d-vpi 67ppd
ldr](https://github.com/bevyengine/bevy/assets/302146/a2ec471c-f576-4a36-a23b-b24b22578b97)

```
     Mean: 0.001214
     Weighted median: 0.937499
     1st weighted quartile: 0.635467
     3rd weighted quartile: 0.979085
     Min: 0.000000
     Max: 0.988971
     Evaluation time: 0.4462 seconds
```

### 2D Sprite `bevymark --benchmark --waves 160 --per-wave 1000 --mode
sprite`

<img width="1396" alt="Screenshot 2023-09-04 at 12 21 12"
src="https://github.com/bevyengine/bevy/assets/302146/8b31e915-d6be-4cac-abf5-c6a4da9c3d43">
This just spawns 160 waves of 1000 sprites. There should be and is no
notable difference between main and the PR.

### 2D Sprite `bevymark --benchmark --waves 160 --per-wave 1000 --mode
sprite --material-texture-count 10`

<img width="1389" alt="Screenshot 2023-09-04 at 12 36 08"
src="https://github.com/bevyengine/bevy/assets/302146/45fe8d6d-c901-4062-a349-3693dd044413">
This spawns the sprites selecting a texture at random per instance from
the 10 generated textures. This has no significant change vs main and
shouldn't.

### 2D Sprite `bevymark --benchmark --waves 160 --per-wave 1000 --mode
sprite --vary-per-instance`

<img width="1401" alt="Screenshot 2023-09-04 at 12 29 52"
src="https://github.com/bevyengine/bevy/assets/302146/762c5c60-352e-471f-8dbe-bbf10e24ebd6">
This sets the sprite colour as being unique per instance. This can still
all be drawn using one batch. There should be no difference but the PR
produces median frame times that are 4% higher. Investigation showed no
clear sources of cost, rather a mix of give and take that should not
happen. It seems like noise in the results.

### Summary

| Benchmark  | % change in median frame time |
| ------------- | ------------- |
| many_cubes  | 🟩 -30%  |
| many_cubes 10 materials  | 🟩 -5%  |
| many_cubes unique materials  | 🟩 ~0%  |
| bevymark mesh2d  | 🟩 -50%  |
| bevymark mesh2d 10 materials  | 🟩 -50%  |
| bevymark mesh2d unique materials  | 🟩 -7%  |
| bevymark sprite  | 🟥 2%  |
| bevymark sprite 10 materials  | 🟥 0.6%  |
| bevymark sprite unique materials  | 🟥 4.1%  |

---

## Changelog

- Added: 2D and 3D mesh entities that share the same mesh and material
(same textures, same data) are now batched into the same draw command
for better performance.

---------

Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
Co-authored-by: Nicola Papale <nico@nicopap.ch>
2023-09-21 22:12:34 +00:00
Nicola Papale
ee3cc8ca86
Fix erronenous glam version (#9653)
# Objective

- Fix compilation issue with wrongly specified glam version
- bevy uses `Vec2::INFINITY`, depends on `0.24` (equivalent to `0.24.0`)
yet it was only introduced in version `0.24.1`

Context:
https://discord.com/channels/691052431525675048/692572690833473578/1146586570787397794

## Solution

- Bump glam version.
2023-08-31 12:55:17 +00:00
Emi
36eedbfa92
Change Urect::width & Urect::height to be const (#9640)
# Objective
The two functions

[`Urect::height`](https://docs.rs/bevy_math/latest/bevy_math/struct.URect.html#method.height),

[`Urect::width`](https://docs.rs/bevy_math/latest/bevy_math/struct.URect.html#method.width)
 are currently not const. 
Since the methods are very unlikely to change (ever) and are useful to
be const for some games, they should be.

Co-authored-by: Emi <emanuel.boehm@gmail.com>
2023-08-30 17:31:30 +00:00
jnhyatt
087a345579
Rename Bezier to CubicBezier for clarity (#9554)
# Objective

A Bezier curve is a curve defined by two or more control points. In the
simplest form, it's just a line. The (arguably) most common type of
Bezier curve is a cubic Bezier, defined by four control points. These
are often used in animation, etc. Bevy has a Bezier curve struct called
`Bezier`. However, this is technically a misnomer as it only represents
cubic Bezier curves.

## Solution

This PR changes the struct name to `CubicBezier` to more accurately
reflect the struct's usage. Since it's exposed in Bevy's prelude, it can
potentially collide with other `Bezier` implementations. While that
might instead be an argument for removing it from the prelude, there's
also something to be said for adding a more general `Bezier` into Bevy,
in which case we'd likely want to use the name `Bezier`. As a final
motivator, not only is the struct located in `cubic_spines.rs`, there
are also several other spline-related structs which follow the
`CubicXxx` naming convention where applicable. For example,
`CubicSegment` represents a cubic Bezier curve (with coefficients
pre-baked).

---

## Migration Guide

- Change all `Bezier` references to `CubicBezier`
2023-08-28 17:37:42 +00:00
Rob Parrett
a788e31ad5
Fix CI for Rust 1.72 (#9562)
# Objective

[Rust 1.72.0](https://blog.rust-lang.org/2023/08/24/Rust-1.72.0.html) is
now stable.

# Notes

- `let-else` formatting has arrived!
- I chose to allow `explicit_iter_loop` due to
https://github.com/rust-lang/rust-clippy/issues/11074.
  
We didn't hit any of the false positives that prevent compilation, but
fixing this did produce a lot of the "symbol soup" mentioned, e.g. `for
image in &mut *image_events {`.
  
  Happy to undo this if there's consensus the other way.

---------

Co-authored-by: François <mockersf@gmail.com>
2023-08-25 12:34:24 +00:00
Robert Swain
0a11af9375
Reduce the size of MeshUniform to improve performance (#9416)
# Objective

- Significantly reduce the size of MeshUniform by only including
necessary data.

## Solution

Local to world, model transforms are affine. This means they only need a
4x3 matrix to represent them.

`MeshUniform` stores the current, and previous model transforms, and the
inverse transpose of the current model transform, all as 4x4 matrices.
Instead we can store the current, and previous model transforms as 4x3
matrices, and we only need the upper-left 3x3 part of the inverse
transpose of the current model transform. This change allows us to
reduce the serialized MeshUniform size from 208 bytes to 144 bytes,
which is over a 30% saving in data to serialize, and VRAM bandwidth and
space.

## Benchmarks

On an M1 Max, running `many_cubes -- sphere`, main is in yellow, this PR
is in red:
<img width="1484" alt="Screenshot 2023-08-11 at 02 36 43"
src="https://github.com/bevyengine/bevy/assets/302146/7d99c7b3-f2bb-4004-a8d0-4c00f755cb0d">
A reduction in frame time of ~14%.

---

## Changelog

- Changed: Redefined `MeshUniform` to improve performance by using 4x3
affine transforms and reconstructing 4x4 matrices in the shader. Helper
functions were added to `bevy_pbr::mesh_functions` to unpack the data.
`affine_to_square` converts the packed 4x3 in 3x4 matrix data to a 4x4
matrix. `mat2x4_f32_to_mat3x3` converts the 3x3 in mat2x4 + f32 matrix
data back into a 3x3.

## Migration Guide

Shader code before:
```
var model = mesh[instance_index].model;
```

Shader code after:
```
#import bevy_pbr::mesh_functions affine_to_square

var model = affine_to_square(mesh[instance_index].model);
```
2023-08-15 06:00:23 +00:00
Tristan Guichaoua
37915e1d93
Add glam swizzles traits to prelude (#9387)
# Objective

Add possibility to use the glam's swizzles traits without having to
manually import them.

```diff
use bevy::prelude::*;
- use bevy::math::Vec3Swizzles;

fn foo(x: Vec3) {
    let y: Vec2 = x.xy();
}
```

## Solution

Add the swizzles traits to bevy's prelude.

---

## Changelog

- `Vec2Swizzles`, `Vec3Swizzles` and `Vec4Swizzles` are now part of the
prelude.
2023-08-10 17:05:01 +00:00
Arnav Mummineni
bc8e2746d7
Add reflect impls to IRect and URect (#9191)
# Objective

This attempts to make the new IRect and URect structs in bevy_math more
similar to the existing Rect struct.

## Solution

Add reflect implementations for IRect and URect, since one already
exists for Rect.
2023-07-23 01:02:00 +00:00
Ame
7154b59438
Return URect instead of (UVec2, UVec2) in Camera::physical_viewport_rect (#9085)
# Objective

Continue #7867 now that we have URect #7984
- Return `URect` instead of `(UVec2, UVec2)` in
`Camera::physical_viewport_rect`
 - Add `URect` and `IRect` to prelude

## Changelog

- Changed `Camera::physical_viewport_rect` return type from `(UVec2,
UVec2)` to `URect`
- `URect` and `IRect` were added to prelude

## Migration Guide

Before:

```rust
fn view_physical_camera_rect(camera_query: Query<&Camera>) {
    let camera = camera_query.single();
    let Some((min, max)) = camera.physical_viewport_rect() else { return };
    dbg!(min, max);
}
```

After:

```rust
fn view_physical_camera_rect(camera_query: Query<&Camera>) {
    let camera = camera_query.single();
    let Some(URect { min, max }) = camera.physical_viewport_rect() else { return };
    dbg!(min, max);
}
```
2023-07-15 21:25:22 +00:00
Arnav Mummineni
94b574ad16
Rename bevy_math::rects conversion methods (#9159)
# Objective

Some of the conversion methods on the new rect types introduced in #7984
have misleading names.

## Solution

Rename all methods returning an `IRect` to `as_irect` and all methods
returning a `URect` to `as_urect`.

## Migration Guide

Replace uses of the old method names with the new method names.
2023-07-15 21:10:39 +00:00
Carter Anderson
7c3131a761
Bump Version after Release (#9106)
CI-capable version of #9086

---------

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François <mockersf@gmail.com>
2023-07-10 21:19:27 +00:00
Carter Anderson
8ba9571eed
Release 0.11.0 (#9080)
I created this manually as Github didn't want to run CI for the
workflow-generated PR. I'm guessing we didn't hit this in previous
releases because we used bors.

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
2023-07-09 08:43:47 +00:00
Liam Gallagher
942766c485
Add integer equivalents for Rect (#7984)
## Objective

Add integer equivalents for the `Rect` type.

Closes #7967

## Solution

- Add `IRect` and `URect`

## Changelog

Added `IRect` and `URect` types.
2023-06-12 19:10:48 +00:00
Nicola Papale
c8167c1276
Add CubicCurve::segment_count + iter_samples adjustment (#8711)
## Objective

- Provide a way to use `CubicCurve` non-iter methods
- Accept a `FnMut` over a `fn` pointer on `iter_samples`
- Improve `build_*_cubic_100_points` benchmark by -45% (this means they
are twice as fast)

### Solution

Previously, the only way to iterate over an evenly spaced set of points
on a `CubicCurve` was to use one of the `iter_*` methods.

The return value of those methods were bound by `&self` lifetime, making
them unusable in certain contexts.

Furthermore, other `CubicCurve` methods (`position`, `velocity`,
`acceleration`) required normalizing `t` over the `CubicCurve`'s
internal segment count.

There were no way to access this segment count, making those methods
pretty much unusable.

The newly added `segment_count` allows accessing the segment count.

`iter_samples` used to accept a `fn`, a function pointer. This is
surprising and contrary to the rust stdlib APIs, which accept `Fn`
traits for `Iterator` combinators.

`iter_samples` now accepts a `FnMut`.

I don't trust a bit the bevy benchmark suit, but according to it, this
doubles (-45%) the performance on the `build_pos_cubic_100_points` and
`build_accel_cubic_100_points` benchmarks.

---

## Changelog

- Added the `CubicCurve::segments` method to access the underlying
segments of a cubic curve
- Allow closures as `CubicCurve::iter_samples` `sample_function`
argument.
2023-05-31 14:57:37 +00:00
François
0736195a1e
update syn, encase, glam and hexasphere (#8573)
# Objective

- Fixes #8282 
- Update `syn` to 2.0, `encase` to 0.6, `glam` to 0.24 and `hexasphere`
to 9.0


Blocked ~~on https://github.com/teoxoy/encase/pull/42~~ and ~~on
https://github.com/OptimisticPeach/hexasphere/pull/17~~

---------

Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
Co-authored-by: JoJoJet <21144246+JoJoJet@users.noreply.github.com>
2023-05-16 01:24:17 +00:00
JoJoJet
3ead10a3e0
Suppress the clippy::type_complexity lint (#8313)
# Objective

The clippy lint `type_complexity` is known not to play well with bevy.
It frequently triggers when writing complex queries, and taking the
lint's advice of using a type alias almost always just obfuscates the
code with no benefit. Because of this, this lint is currently ignored in
CI, but unfortunately it still shows up when viewing bevy code in an
IDE.

As someone who's made a fair amount of pull requests to this repo, I
will say that this issue has been a consistent thorn in my side. Since
bevy code is filled with spurious, ignorable warnings, it can be very
difficult to spot the *real* warnings that must be fixed -- most of the
time I just ignore all warnings, only to later find out that one of them
was real after I'm done when CI runs.

## Solution

Suppress this lint in all bevy crates. This was previously attempted in
#7050, but the review process ended up making it more complicated than
it needs to be and landed on a subpar solution.

The discussion in https://github.com/rust-lang/rust-clippy/pull/10571
explores some better long-term solutions to this problem. Since there is
no timeline on when these solutions may land, we should resolve this
issue in the meantime by locally suppressing these lints.

### Unresolved issues

Currently, these lints are not suppressed in our examples, since that
would require suppressing the lint in every single source file. They are
still ignored in CI.
2023-04-06 21:27:36 +00:00
Jannik Obermann
f201a9df39
Fix CubicCurve::iter_samples iteration count (#8049)
# Objective

Fix `CubicCurve::iter_samples` iteration count.

## Solution

If I understand the function and the docs correctly, this should iterate
over `0..=subdivisions` instead of `0..subdivisions`.
For example: Now the iteration returns 3 points at `subdivisions = 2`,
as indicated in the documentation.
2023-03-31 08:15:21 +00:00