bevy/crates
JoshValjosh ddee5cca85
Improve Bevy's double-precision story for third-party crates (#19194)
# Objective

Certain classes of games, usually those with enormous worlds, require
some amount of support for double-precision. Libraries like `big_space`
exist to allow for large worlds while integrating cleanly with Bevy's
primarily single-precision ecosystem, but even then, games will often
still work directly in double-precision throughout the part of the
pipeline that feeds into the Bevy interface.

Currently, working with double-precision types in Bevy is a pain. `glam`
provides types like `DVec3`, but Bevy doesn't provide double-precision
analogs for `glam` wrappers like `Dir3`. This is mostly because doing so
involves one of:

- code duplication
- generics
- templates (like `glam` uses)
- macros

Each of these has issues that are enough to be deal-breakers as far as
maintainability, usability or readability. To work around this, I'm
putting together `bevy_dmath`, a crate that duplicates `bevy_math` types
and functionality to allow downstream users to enjoy the ergonomics and
power of `bevy_math` in double-precision. For the most part, it's a
smooth process, but in order to fully integrate, there are some
necessary changes that can only be made in `bevy_math`.

## Solution

This PR addresses the first and easiest issue with downstream
double-precision math support: `VectorSpace` currently can only
represent vector spaces over `f32`. This automatically closes the door
to double-precision curves, among other things. This restriction can be
easily lifted by allowing vector spaces to specify the underlying scalar
field. This PR adds a new trait `ScalarField` that satisfies the
properties of a scalar field (the ones that can be upheld statically)
and adds a new associated type `type Scalar: ScalarField` to
`VectorSpace`. It's mostly an unintrusive change. The biggest annoyances
are:

- it touches a lot of curve code
- `bevy_math::ops` doesn't support `f64`, so there are some annoying
workarounds

As far as curves code, I wanted to make this change unintrusive and
bite-sized, so I'm trying to touch as little code as possible. To prove
to myself it can be done, I went ahead and (*not* in this PR) migrated
most of the curves API to support different `ScalarField`s and it went
really smoothly! The ugliest thing was adding `P::Scalar: From<usize>`
in several places. There's an argument to be made here that we should be
using `num-traits`, but that's not immediately relevant. The point is
that for now, the smallest change I could make was to go into every
curve impl and make them generic over `VectorSpace<Scalar = f32>`.
Curves work exactly like before and don't change the user API at all.

# Follow-up

- **Extend `bevy_math::ops` to work with `f64`.** `bevy_math::ops` is
used all over, and if curves are ever going to support different
`ScalarField` types, we'll need to be able to use the correct `std` or
`libm` ops for `f64` types as well. Adding an `ops64` mod turned out to
be really ugly, but I'll point out the maintenance burden is low because
we're not going to be adding new floating-point ops anytime soon.
Another solution is to build a floating-point trait that calls the right
op variant and impl it for `f32` and `f64`. This reduces maintenance
burden because on the off chance we ever *do* want to go modify it, it's
all tied together: you can't change the interface on one without
changing the trait, which forces you to update the other. A third option
is to use `num-traits`, which is basically option 2 but someone else did
the work for us. They already support `no_std` using `libm`, so it would
be more or less a drop-in replacement. They're missing a couple
floating-point ops like `floor` and `ceil`, but we could make our own
floating-point traits for those (there's even the potential for
upstreaming them into `num-traits`).
- **Tweak curves to accept vector spaces over any `ScalarField`.**
Curves are ready to support custom scalar types as soon as the bullet
above is addressed. I will admit that the code is not as fun to look at:
`P::Scalar` instead of `f32` everywhere. We could consider an alternate
design where we use `f32` even to interpolate something like a `DVec3`,
but personally I think that's a worse solution than parameterizing
curves over the vector space's scalar type. At the end of the day, it's
not really bad to deal with in my opinion... `ScalarType` supports
enough operations that working with them is almost like working with raw
float types, and it unlocks a whole ecosystem for games that want to use
double-precision.
2025-06-08 02:02:47 +00:00
..
bevy_a11y bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_animation Improve Bevy's double-precision story for third-party crates (#19194) 2025-06-08 02:02:47 +00:00
bevy_anti_aliasing bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_app generic component propagation (#17575) 2025-06-06 00:02:02 +00:00
bevy_asset bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_audio bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_color Improve Bevy's double-precision story for third-party crates (#19194) 2025-06-08 02:02:47 +00:00
bevy_core_pipeline bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_derive bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_dev_tools bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_diagnostic bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_dylib bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_ecs Replace (Partial)Ord for EntityGeneration with corrected standalone method (#19432) 2025-06-07 22:29:13 +00:00
bevy_encase_derive bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_gilrs bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_gizmos bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_gltf bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_image bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_input bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_input_focus bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_internal bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_log bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_macro_utils bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_math Improve Bevy's double-precision story for third-party crates (#19194) 2025-06-08 02:02:47 +00:00
bevy_mesh bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_mikktspace bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_pbr bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_picking Mention in the docs for pointer events that these are in screen-space. (#19518) 2025-06-06 22:20:14 +00:00
bevy_platform bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_ptr bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_reflect bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_remote Only get valid component ids (#19510) 2025-06-06 20:59:57 +00:00
bevy_render bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_scene Only get valid component ids (#19510) 2025-06-06 20:59:57 +00:00
bevy_sprite bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_state bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_tasks bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_text Remove re-exports of cosmic_text types (#19516) 2025-06-06 21:49:02 +00:00
bevy_time bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_transform bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_ui bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_utils bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_window bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00
bevy_winit bevyengine.org -> bevy.org (#19503) 2025-06-05 23:09:28 +00:00