mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
Curve
gizmos integration (#14971)
# Objective - Add gizmos integration for the new `Curve` things in the math lib ## Solution - Add the following methods - `curve_2d(curve, sample_times, color)` - `curve_3d(curve, sample_times, color)` - `curve_gradient_2d(curve, sample_times_with_colors)` - `curve_gradient_3d(curve, sample_times_with_colors)` ## Testing - I added examples of the 2D and 3D variants of the gradient curve gizmos to the gizmos examples. ## Showcase ### 2D ![image](https://github.com/user-attachments/assets/01a75706-a7b4-4fc5-98d5-18018185c877) ```rust let domain = Interval::EVERYWHERE; let curve = function_curve(domain, |t| Vec2::new(t, (t / 25.0).sin() * 100.0)); let resolution = ((time.elapsed_seconds().sin() + 1.0) * 50.0) as usize; let times_and_colors = (0..=resolution) .map(|n| n as f32 / resolution as f32) .map(|t| (t - 0.5) * 600.0) .map(|t| (t, TEAL.mix(&HOT_PINK, (t + 300.0) / 600.0))); gizmos.curve_gradient_2d(curve, times_and_colors); ``` ### 3D ![image](https://github.com/user-attachments/assets/3fd23983-1ec9-46cd-baed-5b5e2dc935d0) ```rust let domain = Interval::EVERYWHERE; let curve = function_curve(domain, |t| { (Vec2::from((t * 10.0).sin_cos())).extend(t - 6.0) }); let resolution = ((time.elapsed_seconds().sin() + 1.0) * 100.0) as usize; let times_and_colors = (0..=resolution) .map(|n| n as f32 / resolution as f32) .map(|t| t * 5.0) .map(|t| (t, TEAL.mix(&HOT_PINK, t / 5.0))); gizmos.curve_gradient_3d(curve, times_and_colors); ```
This commit is contained in:
parent
1cca4f2968
commit
9e78433427
5 changed files with 197 additions and 0 deletions
175
crates/bevy_gizmos/src/curves.rs
Normal file
175
crates/bevy_gizmos/src/curves.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
//! Additional [`Gizmos`] Functions -- Curves
|
||||
//!
|
||||
//! Includes the implementation of [`Gizmos::curve_2d`],
|
||||
//! [`Gizmos::curve_3d`] and assorted support items.
|
||||
|
||||
use bevy_color::Color;
|
||||
use bevy_math::{curve::Curve, Vec2, Vec3};
|
||||
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
|
||||
impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear>
|
||||
where
|
||||
Config: GizmoConfigGroup,
|
||||
Clear: 'static + Send + Sync,
|
||||
{
|
||||
/// Draw a curve, at the given time points, sampling in 2D.
|
||||
///
|
||||
/// This should be called for each frame the curve needs to be rendered.
|
||||
///
|
||||
/// Samples of time points outside of the curve's domain will be filtered out and won't
|
||||
/// contribute to the rendering. If you wish to render the curve outside of its domain you need
|
||||
/// to create a new curve with an extended domain.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `curve_2d` some type that implements the [`Curve`] trait and samples `Vec2`s
|
||||
/// - `times` some iterable type yielding `f32` which will be used for sampling the curve
|
||||
/// - `color` the color of the curve
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use bevy_gizmos::prelude::*;
|
||||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::{RED};
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// let domain = Interval::UNIT;
|
||||
/// let curve = function_curve(domain, |t| Vec2::from(t.sin_cos()));
|
||||
/// gizmos.curve_2d(curve, (0..=100).map(|n| n as f32 / 100.0), RED);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
pub fn curve_2d(
|
||||
&mut self,
|
||||
curve_2d: impl Curve<Vec2>,
|
||||
times: impl IntoIterator<Item = f32>,
|
||||
color: impl Into<Color>,
|
||||
) {
|
||||
self.linestrip_2d(curve_2d.sample_iter(times).flatten(), color);
|
||||
}
|
||||
|
||||
/// Draw a curve, at the given time points, sampling in 3D.
|
||||
///
|
||||
/// This should be called for each frame the curve needs to be rendered.
|
||||
///
|
||||
/// Samples of time points outside of the curve's domain will be filtered out and won't
|
||||
/// contribute to the rendering. If you wish to render the curve outside of its domain you need
|
||||
/// to create a new curve with an extended domain.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `curve_3d` some type that implements the [`Curve`] trait and samples `Vec3`s
|
||||
/// - `times` some iterable type yielding `f32` which will be used for sampling the curve
|
||||
/// - `color` the color of the curve
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use bevy_gizmos::prelude::*;
|
||||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::{RED};
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// let domain = Interval::UNIT;
|
||||
/// let curve = function_curve(domain, |t| {
|
||||
/// let (x,y) = t.sin_cos();
|
||||
/// Vec3::new(x, y, t)
|
||||
/// });
|
||||
/// gizmos.curve_3d(curve, (0..=100).map(|n| n as f32 / 100.0), RED);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
pub fn curve_3d(
|
||||
&mut self,
|
||||
curve_3d: impl Curve<Vec3>,
|
||||
times: impl IntoIterator<Item = f32>,
|
||||
color: impl Into<Color>,
|
||||
) {
|
||||
self.linestrip(curve_3d.sample_iter(times).flatten(), color);
|
||||
}
|
||||
|
||||
/// Draw a curve, at the given time points, sampling in 2D, with a color gradient.
|
||||
///
|
||||
/// This should be called for each frame the curve needs to be rendered.
|
||||
///
|
||||
/// Samples of time points outside of the curve's domain will be filtered out and won't
|
||||
/// contribute to the rendering. If you wish to render the curve outside of its domain you need
|
||||
/// to create a new curve with an extended domain.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `curve_2d` some type that implements the [`Curve`] trait and samples `Vec2`s
|
||||
/// - `times_with_colors` some iterable type yielding `f32` which will be used for sampling
|
||||
/// the curve together with the color at this position
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use bevy_gizmos::prelude::*;
|
||||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::{Mix, palettes::basic::{GREEN, RED}};
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// let domain = Interval::UNIT;
|
||||
/// let curve = function_curve(domain, |t| Vec2::from(t.sin_cos()));
|
||||
/// gizmos.curve_gradient_2d(
|
||||
/// curve,
|
||||
/// (0..=100).map(|n| n as f32 / 100.0)
|
||||
/// .map(|t| (t, GREEN.mix(&RED, t)))
|
||||
/// );
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
pub fn curve_gradient_2d<C>(
|
||||
&mut self,
|
||||
curve_2d: impl Curve<Vec2>,
|
||||
times_with_colors: impl IntoIterator<Item = (f32, C)>,
|
||||
) where
|
||||
C: Into<Color>,
|
||||
{
|
||||
self.linestrip_gradient_2d(
|
||||
times_with_colors
|
||||
.into_iter()
|
||||
.filter_map(|(time, color)| curve_2d.sample(time).map(|sample| (sample, color))),
|
||||
);
|
||||
}
|
||||
|
||||
/// Draw a curve, at the given time points, sampling in 3D, with a color gradient.
|
||||
///
|
||||
/// This should be called for each frame the curve needs to be rendered.
|
||||
///
|
||||
/// Samples of time points outside of the curve's domain will be filtered out and won't
|
||||
/// contribute to the rendering. If you wish to render the curve outside of its domain you need
|
||||
/// to create a new curve with an extended domain.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `curve_3d` some type that implements the [`Curve`] trait and samples `Vec3`s
|
||||
/// - `times_with_colors` some iterable type yielding `f32` which will be used for sampling
|
||||
/// the curve together with the color at this position
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use bevy_gizmos::prelude::*;
|
||||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::{Mix, palettes::basic::{GREEN, RED}};
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// let domain = Interval::UNIT;
|
||||
/// let curve = function_curve(domain, |t| {
|
||||
/// let (x,y) = t.sin_cos();
|
||||
/// Vec3::new(x, y, t)
|
||||
/// });
|
||||
/// gizmos.curve_gradient_3d(
|
||||
/// curve,
|
||||
/// (0..=100).map(|n| n as f32 / 100.0)
|
||||
/// .map(|t| (t, GREEN.mix(&RED, t)))
|
||||
/// );
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
pub fn curve_gradient_3d<C>(
|
||||
&mut self,
|
||||
curve_3d: impl Curve<Vec3>,
|
||||
times_with_colors: impl IntoIterator<Item = (f32, C)>,
|
||||
) where
|
||||
C: Into<Color>,
|
||||
{
|
||||
self.linestrip_gradient(
|
||||
times_with_colors
|
||||
.into_iter()
|
||||
.filter_map(|(time, color)| curve_3d.sample(time).map(|sample| (sample, color))),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ pub mod arrows;
|
|||
pub mod circles;
|
||||
pub mod config;
|
||||
pub mod cross;
|
||||
pub mod curves;
|
||||
pub mod gizmos;
|
||||
pub mod grid;
|
||||
pub mod primitives;
|
||||
|
|
|
@ -55,6 +55,7 @@ pub mod prelude {
|
|||
CubicHermite, CubicNurbs, CubicNurbsError, CubicSegment, CyclicCubicGenerator,
|
||||
RationalCurve, RationalGenerator, RationalSegment,
|
||||
},
|
||||
curve::*,
|
||||
direction::{Dir2, Dir3, Dir3A},
|
||||
primitives::*,
|
||||
BVec2, BVec3, BVec4, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Isometry2d,
|
||||
|
|
|
@ -73,6 +73,15 @@ fn draw_example_collection(
|
|||
FUCHSIA,
|
||||
);
|
||||
|
||||
let domain = Interval::EVERYWHERE;
|
||||
let curve = function_curve(domain, |t| Vec2::new(t, (t / 25.0).sin() * 100.0));
|
||||
let resolution = ((time.elapsed_seconds().sin() + 1.0) * 50.0) as usize;
|
||||
let times_and_colors = (0..=resolution)
|
||||
.map(|n| n as f32 / resolution as f32)
|
||||
.map(|t| (t - 0.5) * 600.0)
|
||||
.map(|t| (t, TEAL.mix(&HOT_PINK, (t + 300.0) / 600.0)));
|
||||
gizmos.curve_gradient_2d(curve, times_and_colors);
|
||||
|
||||
my_gizmos
|
||||
.rounded_rect_2d(Isometry2d::IDENTITY, Vec2::splat(630.), BLACK)
|
||||
.corner_radius((time.elapsed_seconds() / 3.).cos() * 100.);
|
||||
|
|
|
@ -131,6 +131,17 @@ fn draw_example_collection(
|
|||
FUCHSIA,
|
||||
);
|
||||
|
||||
let domain = Interval::EVERYWHERE;
|
||||
let curve = function_curve(domain, |t| {
|
||||
(Vec2::from((t * 10.0).sin_cos())).extend(t - 6.0)
|
||||
});
|
||||
let resolution = ((time.elapsed_seconds().sin() + 1.0) * 100.0) as usize;
|
||||
let times_and_colors = (0..=resolution)
|
||||
.map(|n| n as f32 / resolution as f32)
|
||||
.map(|t| t * 5.0)
|
||||
.map(|t| (t, TEAL.mix(&HOT_PINK, t / 5.0)));
|
||||
gizmos.curve_gradient_3d(curve, times_and_colors);
|
||||
|
||||
my_gizmos.sphere(
|
||||
Isometry3d::from_translation(Vec3::new(1., 0.5, 0.)),
|
||||
0.5,
|
||||
|
|
Loading…
Reference in a new issue