mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
3484bd916f
# Objective Fill a gap in the functionality of our curve constructions by allowing users to easily build cyclic curves from control data. ## Solution Here I opted for something lightweight and discoverable. There is a new `CyclicCubicGenerator` trait with a method `to_curve_cyclic` which uses splines' control data to create curves that are cyclic. For now, its signature is exactly like that of `CubicGenerator` — `to_curve_cyclic` just yields a `CubicCurve`: ```rust /// Implement this on cubic splines that can generate a cyclic cubic curve from their spline parameters. /// /// This makes sense only when the control data can be interpreted cyclically. pub trait CyclicCubicGenerator<P: VectorSpace> { /// Build a cyclic [`CubicCurve`] by computing the interpolation coefficients for each curve segment. fn to_curve_cyclic(&self) -> CubicCurve<P>; } ``` This trait has been implemented for `CubicHermite`, `CubicCardinalSpline`, `CubicBSpline`, and `LinearSpline`: <img width="753" alt="Screenshot 2024-07-01 at 8 58 27 PM" src="https://github.com/bevyengine/bevy/assets/2975848/69ae0802-3b78-4fb9-b73a-6f842cf3b33c"> <img width="628" alt="Screenshot 2024-07-01 at 9 00 14 PM" src="https://github.com/bevyengine/bevy/assets/2975848/2992175a-a96c-40fc-b1a1-5206c3572cde"> <img width="606" alt="Screenshot 2024-07-01 at 8 59 36 PM" src="https://github.com/bevyengine/bevy/assets/2975848/9e99eb3a-dbe6-42da-886c-3d3e00410d03"> <img width="603" alt="Screenshot 2024-07-01 at 8 59 01 PM" src="https://github.com/bevyengine/bevy/assets/2975848/d037bc0c-396a-43af-ab5c-fad9a29417ef"> (Each type pictured respectively with the control points rendered as green spheres; tangents not pictured in the case of the Hermite spline.) These curves are all parametrized so that the output of `to_curve` and the output of `to_curve_cyclic` are similar. For instance, in `CubicCardinalSpline`, the first output segment is a curve segment joining the first and second control points in each, although it is constructed differently. In the other cases, the segments from `to_curve` are a subset of those in `to_curve_cyclic`, with the new segments appearing at the end. ## Testing I rendered cyclic splines from control data and made sure they looked reasonable. Existing tests are intact for splines where previous code was modified. (Note that the coefficient computation for cyclic spline segments is almost verbatim identical to that of their non-cyclic counterparts.) The Bezier benchmarks also look fine. --- ## Changelog - Added `CyclicCubicGenerator` trait to `bevy_math::cubic_splines` for creating cyclic curves from control data. - Implemented `CyclicCubicGenerator` for `CubicHermite`, `CubicCardinalSpline`, `CubicBSpline`, and `LinearSpline`. - `bevy_math` now depends on `itertools`. --- ## Discussion ### Design decisions The biggest thing here is just the approach taken in the first place: namely, the cyclic constructions use new methods on the same old structs. This choice was made to reduce friction and increase discoverability but also because creating new ones just seemed unnecessary: the underlying data would have been the same, so creating something like "`CyclicCubicBSpline`" whose internally-held control data is regarded as cyclic in nature doesn't really accomplish much — the end result for the user is basically the same either way. Similarly, I don't presently see a pressing need for `to_curve_cyclic` to output something other than a `CubicCurve`, although changing this in the future may be useful. See below. A notable omission here is that `CyclicCubicGenerator` is not implemented for `CubicBezier`. This is not a gap waiting to be filled — `CubicBezier` just doesn't have enough data to join its start with its end without just making up the requisite control points wholesale. In all the cases where `CyclicCubicGenerator` has been implemented here, the fashion in which the ends are connected is quite natural and follows the semantics of the associated spline construction. ### Future direction There are two main things here: 1. We should investigate whether we should do something similar for NURBS. I just don't know that much about NURBS at the moment, so I regarded this as out of scope for the PR. 2. We may eventually want to change the output type of `CyclicCubicGenerator::to_curve_cyclic` to a type which reifies the cyclic nature of the curve output. This wasn't done in this PR because I'm unsure how much value a type-level guarantee of cyclicity actually has, but if some useful features make sense only in the case of cyclic curves, this might be worth pursuing.
61 lines
2.1 KiB
TOML
61 lines
2.1 KiB
TOML
[package]
|
|
name = "bevy_math"
|
|
version = "0.15.0-dev"
|
|
edition = "2021"
|
|
description = "Provides math functionality for Bevy Engine"
|
|
homepage = "https://bevyengine.org"
|
|
repository = "https://github.com/bevyengine/bevy"
|
|
license = "MIT OR Apache-2.0"
|
|
keywords = ["bevy"]
|
|
rust-version = "1.68.2"
|
|
|
|
[dependencies]
|
|
glam = { version = "0.27", features = ["bytemuck"] }
|
|
thiserror = "1.0"
|
|
itertools = "0.13.0"
|
|
serde = { version = "1", features = ["derive"], optional = true }
|
|
libm = { version = "0.2", optional = true }
|
|
approx = { version = "0.5", optional = true }
|
|
rand = { version = "0.8", features = [
|
|
"alloc",
|
|
], default-features = false, optional = true }
|
|
rand_distr = { version = "0.4.3", optional = true }
|
|
smallvec = { version = "1.11" }
|
|
|
|
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
|
"glam",
|
|
], optional = true }
|
|
|
|
[dev-dependencies]
|
|
approx = "0.5"
|
|
# Supply rngs for examples and tests
|
|
rand = "0.8"
|
|
rand_chacha = "0.3"
|
|
# Enable the approx feature when testing.
|
|
bevy_math = { path = ".", version = "0.15.0-dev", features = ["approx"] }
|
|
glam = { version = "0.27", features = ["approx"] }
|
|
|
|
|
|
[features]
|
|
default = ["rand", "bevy_reflect"]
|
|
serialize = ["dep:serde", "glam/serde"]
|
|
# Enable approx for glam types to approximate floating point equality comparisons and assertions
|
|
approx = ["dep:approx", "glam/approx"]
|
|
# Enable interoperation of glam types with mint-compatible libraries
|
|
mint = ["glam/mint"]
|
|
# Enable libm mathematical functions for glam types to ensure consistent outputs
|
|
# across platforms at the cost of losing hardware-level optimization using intrinsics
|
|
libm = ["dep:libm", "glam/libm"]
|
|
# Enable assertions to check the validity of parameters passed to glam
|
|
glam_assert = ["glam/glam-assert"]
|
|
# Enable assertions in debug builds to check the validity of parameters passed to glam
|
|
debug_glam_assert = ["glam/debug-glam-assert"]
|
|
# Enable the rand dependency for shape_sampling
|
|
rand = ["dep:rand", "dep:rand_distr", "glam/rand"]
|
|
|
|
[lints]
|
|
workspace = true
|
|
|
|
[package.metadata.docs.rs]
|
|
rustdoc-args = ["-Zunstable-options", "--cfg", "docsrs"]
|
|
all-features = true
|