mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
Use Isometry
in bevy_gizmos
wherever we can (#14676)
# Objective - Solves the last bullet in and closes #14319 - Make better use of the `Isometry` types - Prevent issues like #14655 - Probably simplify and clean up a lot of code through the use of Gizmos as well (i.e. the 3D gizmos for cylinders circles & lines don't connect well, probably due to wrong rotations) ## Solution - go through the `bevy_gizmos` crate and give all methods a slight workover ## Testing - For all the changed examples I run `git switch main && cargo rr --example <X> && git switch <BRANCH> && cargo rr --example <X>` and compare the visual results - Check if all doc tests are still compiling - Check the docs in general and update them !!! --- ## Migration Guide The gizmos methods function signature changes as follows: - 2D - if it took `position` & `rotation_angle` before -> `Isometry2d::new(position, Rot2::radians(rotation_angle))` - if it just took `position` before -> `Isometry2d::from_translation(position)` - 3D - if it took `position` & `rotation` before -> `Isometry3d::new(position, rotation)` - if it just took `position` before -> `Isometry3d::from_translation(position)`
This commit is contained in:
parent
45281e62d7
commit
8895113784
20 changed files with 627 additions and 785 deletions
|
@ -6,7 +6,7 @@
|
|||
use crate::circles::DEFAULT_CIRCLE_RESOLUTION;
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
use bevy_color::Color;
|
||||
use bevy_math::{Isometry2d, Quat, Vec2, Vec3};
|
||||
use bevy_math::{Isometry2d, Isometry3d, Quat, Vec2, Vec3};
|
||||
use std::f32::consts::{FRAC_PI_2, TAU};
|
||||
|
||||
// === 2D ===
|
||||
|
@ -140,9 +140,9 @@ where
|
|||
/// - `angle`: sets how much of a circle circumference is passed, e.g. PI is half a circle. This
|
||||
/// value should be in the range (-2 * PI..=2 * PI)
|
||||
/// - `radius`: distance between the arc and its center point
|
||||
/// - `position`: position of the arcs center point
|
||||
/// - `rotation`: defines orientation of the arc, by default we assume the arc is contained in a
|
||||
/// plane parallel to the XZ plane and the default starting point is (`position + Vec3::X`)
|
||||
/// - `isometry` defines the translation and rotation of the arc.
|
||||
/// - the translation specifies the center of the arc
|
||||
/// - the rotation is counter-clockwise starting from `Vec3::Y`
|
||||
/// - `color`: color of the arc
|
||||
///
|
||||
/// # Builder methods
|
||||
|
@ -163,8 +163,7 @@ where
|
|||
/// .arc_3d(
|
||||
/// 270.0_f32.to_radians(),
|
||||
/// 0.25,
|
||||
/// Vec3::ONE,
|
||||
/// rotation,
|
||||
/// Isometry3d::new(Vec3::ONE, rotation),
|
||||
/// ORANGE
|
||||
/// )
|
||||
/// .resolution(100);
|
||||
|
@ -176,15 +175,13 @@ where
|
|||
&mut self,
|
||||
angle: f32,
|
||||
radius: f32,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> {
|
||||
Arc3dBuilder {
|
||||
gizmos: self,
|
||||
start_vertex: Vec3::X,
|
||||
center: position,
|
||||
rotation,
|
||||
isometry,
|
||||
angle,
|
||||
radius,
|
||||
color: color.into(),
|
||||
|
@ -317,8 +314,7 @@ where
|
|||
Arc3dBuilder {
|
||||
gizmos: self,
|
||||
start_vertex,
|
||||
center,
|
||||
rotation,
|
||||
isometry: Isometry3d::new(center, rotation),
|
||||
angle,
|
||||
radius,
|
||||
color: color.into(),
|
||||
|
@ -344,8 +340,7 @@ where
|
|||
//
|
||||
// DO NOT expose this field to users as it is easy to mess this up
|
||||
start_vertex: Vec3,
|
||||
center: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
angle: f32,
|
||||
radius: f32,
|
||||
color: Color,
|
||||
|
@ -380,8 +375,7 @@ where
|
|||
|
||||
let positions = arc_3d_inner(
|
||||
self.start_vertex,
|
||||
self.center,
|
||||
self.rotation,
|
||||
self.isometry,
|
||||
self.angle,
|
||||
self.radius,
|
||||
resolution,
|
||||
|
@ -392,8 +386,7 @@ where
|
|||
|
||||
fn arc_3d_inner(
|
||||
start_vertex: Vec3,
|
||||
center: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
angle: f32,
|
||||
radius: f32,
|
||||
resolution: u32,
|
||||
|
@ -406,7 +399,8 @@ fn arc_3d_inner(
|
|||
.map(move |frac| frac as f32 / resolution as f32)
|
||||
.map(move |percentage| angle * percentage)
|
||||
.map(move |frac_angle| Quat::from_axis_angle(Vec3::Y, frac_angle) * start_vertex)
|
||||
.map(move |p| rotation * (p * radius) + center)
|
||||
.map(move |vec3| vec3 * radius)
|
||||
.map(move |vec3| isometry * vec3)
|
||||
}
|
||||
|
||||
// helper function for getting a default value for the resolution parameter
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
use bevy_color::Color;
|
||||
use bevy_math::Mat2;
|
||||
use bevy_math::{Dir3, Quat, Vec2, Vec3};
|
||||
use bevy_math::{Isometry2d, Isometry3d};
|
||||
use bevy_math::{Quat, Vec2, Vec3};
|
||||
use std::f32::consts::TAU;
|
||||
|
||||
pub(crate) const DEFAULT_CIRCLE_RESOLUTION: u32 = 32;
|
||||
|
@ -24,7 +24,12 @@ where
|
|||
Config: GizmoConfigGroup,
|
||||
Clear: 'static + Send + Sync,
|
||||
{
|
||||
/// Draw an ellipse in 3D at `position` with the flat side facing `normal`.
|
||||
/// Draw an ellipse in 3D with the given `isometry` applied.
|
||||
///
|
||||
/// If `isometry == Isometry3d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec3::ZERO`
|
||||
/// - the `half_sizes` are aligned with the `Vec3::X` and `Vec3::Y` axes.
|
||||
///
|
||||
/// This should be called for each frame the ellipse needs to be rendered.
|
||||
///
|
||||
|
@ -34,12 +39,12 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::{RED, GREEN};
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.ellipse(Vec3::ZERO, Quat::IDENTITY, Vec2::new(1., 2.), GREEN);
|
||||
/// gizmos.ellipse(Isometry3d::IDENTITY, Vec2::new(1., 2.), GREEN);
|
||||
///
|
||||
/// // Ellipses have 32 line-segments by default.
|
||||
/// // You may want to increase this for larger ellipses.
|
||||
/// gizmos
|
||||
/// .ellipse(Vec3::ZERO, Quat::IDENTITY, Vec2::new(5., 1.), RED)
|
||||
/// .ellipse(Isometry3d::IDENTITY, Vec2::new(5., 1.), RED)
|
||||
/// .resolution(64);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
|
@ -47,22 +52,25 @@ where
|
|||
#[inline]
|
||||
pub fn ellipse(
|
||||
&mut self,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
half_size: Vec2,
|
||||
color: impl Into<Color>,
|
||||
) -> EllipseBuilder<'_, 'w, 's, Config, Clear> {
|
||||
EllipseBuilder {
|
||||
gizmos: self,
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
half_size,
|
||||
color: color.into(),
|
||||
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw an ellipse in 2D.
|
||||
/// Draw an ellipse in 2D with the given `isometry` applied.
|
||||
///
|
||||
/// If `isometry == Isometry2d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec2::ZERO`
|
||||
/// - the `half_sizes` are aligned with the `Vec2::X` and `Vec2::Y` axes.
|
||||
///
|
||||
/// This should be called for each frame the ellipse needs to be rendered.
|
||||
///
|
||||
|
@ -72,12 +80,12 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::{RED, GREEN};
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.ellipse_2d(Vec2::ZERO, 180.0_f32.to_radians(), Vec2::new(2., 1.), GREEN);
|
||||
/// gizmos.ellipse_2d(Isometry2d::from_rotation(Rot2::degrees(180.0)), Vec2::new(2., 1.), GREEN);
|
||||
///
|
||||
/// // Ellipses have 32 line-segments by default.
|
||||
/// // You may want to increase this for larger ellipses.
|
||||
/// gizmos
|
||||
/// .ellipse_2d(Vec2::ZERO, 180.0_f32.to_radians(), Vec2::new(5., 1.), RED)
|
||||
/// .ellipse_2d(Isometry2d::from_rotation(Rot2::degrees(180.0)), Vec2::new(5., 1.), RED)
|
||||
/// .resolution(64);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
|
@ -85,24 +93,25 @@ where
|
|||
#[inline]
|
||||
pub fn ellipse_2d(
|
||||
&mut self,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
half_size: Vec2,
|
||||
color: impl Into<Color>,
|
||||
) -> Ellipse2dBuilder<'_, 'w, 's, Config, Clear> {
|
||||
Ellipse2dBuilder {
|
||||
gizmos: self,
|
||||
position,
|
||||
rotation: Mat2::from_angle(angle),
|
||||
isometry,
|
||||
half_size,
|
||||
color: color.into(),
|
||||
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a circle in 3D at `position` with the flat side facing `normal`.
|
||||
/// Draw a circle in 3D with the given `isometry` applied.
|
||||
///
|
||||
/// This should be called for each frame the circle needs to be rendered.
|
||||
/// If `isometry == Isometry3d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec3::ZERO`
|
||||
/// - the radius is aligned with the `Vec3::X` and `Vec3::Y` axes.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
|
@ -110,12 +119,12 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::{RED, GREEN};
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.circle(Vec3::ZERO, Dir3::Z, 1., GREEN);
|
||||
/// gizmos.circle(Isometry3d::IDENTITY, 1., GREEN);
|
||||
///
|
||||
/// // Circles have 32 line-segments by default.
|
||||
/// // You may want to increase this for larger circles.
|
||||
/// gizmos
|
||||
/// .circle(Vec3::ZERO, Dir3::Z, 5., RED)
|
||||
/// .circle(Isometry3d::IDENTITY, 5., RED)
|
||||
/// .resolution(64);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
|
@ -123,22 +132,25 @@ where
|
|||
#[inline]
|
||||
pub fn circle(
|
||||
&mut self,
|
||||
position: Vec3,
|
||||
normal: Dir3,
|
||||
isometry: Isometry3d,
|
||||
radius: f32,
|
||||
color: impl Into<Color>,
|
||||
) -> EllipseBuilder<'_, 'w, 's, Config, Clear> {
|
||||
EllipseBuilder {
|
||||
gizmos: self,
|
||||
position,
|
||||
rotation: Quat::from_rotation_arc(Vec3::Z, *normal),
|
||||
isometry,
|
||||
half_size: Vec2::splat(radius),
|
||||
color: color.into(),
|
||||
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a circle in 2D.
|
||||
/// Draw a circle in 2D with the given `isometry` applied.
|
||||
///
|
||||
/// If `isometry == Isometry2d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec2::ZERO`
|
||||
/// - the radius is aligned with the `Vec2::X` and `Vec2::Y` axes.
|
||||
///
|
||||
/// This should be called for each frame the circle needs to be rendered.
|
||||
///
|
||||
|
@ -148,12 +160,12 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::{RED, GREEN};
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.circle_2d(Vec2::ZERO, 1., GREEN);
|
||||
/// gizmos.circle_2d(Isometry2d::IDENTITY, 1., GREEN);
|
||||
///
|
||||
/// // Circles have 32 line-segments by default.
|
||||
/// // You may want to increase this for larger circles.
|
||||
/// gizmos
|
||||
/// .circle_2d(Vec2::ZERO, 5., RED)
|
||||
/// .circle_2d(Isometry2d::IDENTITY, 5., RED)
|
||||
/// .resolution(64);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
|
@ -161,21 +173,26 @@ where
|
|||
#[inline]
|
||||
pub fn circle_2d(
|
||||
&mut self,
|
||||
position: Vec2,
|
||||
isometry: Isometry2d,
|
||||
radius: f32,
|
||||
color: impl Into<Color>,
|
||||
) -> Ellipse2dBuilder<'_, 'w, 's, Config, Clear> {
|
||||
Ellipse2dBuilder {
|
||||
gizmos: self,
|
||||
position,
|
||||
rotation: Mat2::IDENTITY,
|
||||
isometry,
|
||||
half_size: Vec2::splat(radius),
|
||||
color: color.into(),
|
||||
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a wireframe sphere in 3D made out of 3 circles around the axes.
|
||||
/// Draw a wireframe sphere in 3D made out of 3 circles around the axes with the given
|
||||
/// `isometry` applied.
|
||||
///
|
||||
/// If `isometry == Isometry3d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec3::ZERO`
|
||||
/// - the 3 circles are in the XY, YZ and XZ planes.
|
||||
///
|
||||
/// This should be called for each frame the sphere needs to be rendered.
|
||||
///
|
||||
|
@ -185,12 +202,12 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::Color;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.sphere(Vec3::ZERO, Quat::IDENTITY, 1., Color::BLACK);
|
||||
/// gizmos.sphere(Isometry3d::IDENTITY, 1., Color::BLACK);
|
||||
///
|
||||
/// // Each circle has 32 line-segments by default.
|
||||
/// // You may want to increase this for larger spheres.
|
||||
/// gizmos
|
||||
/// .sphere(Vec3::ZERO, Quat::IDENTITY, 5., Color::BLACK)
|
||||
/// .sphere(Isometry3d::IDENTITY, 5., Color::BLACK)
|
||||
/// .resolution(64);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
|
@ -198,16 +215,14 @@ where
|
|||
#[inline]
|
||||
pub fn sphere(
|
||||
&mut self,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
radius: f32,
|
||||
color: impl Into<Color>,
|
||||
) -> SphereBuilder<'_, 'w, 's, Config, Clear> {
|
||||
SphereBuilder {
|
||||
gizmos: self,
|
||||
radius,
|
||||
position,
|
||||
rotation: rotation.normalize(),
|
||||
isometry,
|
||||
color: color.into(),
|
||||
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
||||
}
|
||||
|
@ -221,8 +236,7 @@ where
|
|||
Clear: 'static + Send + Sync,
|
||||
{
|
||||
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
half_size: Vec2,
|
||||
color: Color,
|
||||
resolution: u32,
|
||||
|
@ -251,8 +265,7 @@ where
|
|||
}
|
||||
|
||||
let positions = ellipse_inner(self.half_size, self.resolution)
|
||||
.map(|vec2| self.rotation * vec2.extend(0.))
|
||||
.map(|vec3| vec3 + self.position);
|
||||
.map(|vec2| self.isometry * vec2.extend(0.));
|
||||
self.gizmos.linestrip(positions, self.color);
|
||||
}
|
||||
}
|
||||
|
@ -264,8 +277,7 @@ where
|
|||
Clear: 'static + Send + Sync,
|
||||
{
|
||||
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
||||
position: Vec2,
|
||||
rotation: Mat2,
|
||||
isometry: Isometry2d,
|
||||
half_size: Vec2,
|
||||
color: Color,
|
||||
resolution: u32,
|
||||
|
@ -294,9 +306,8 @@ where
|
|||
return;
|
||||
};
|
||||
|
||||
let positions = ellipse_inner(self.half_size, self.resolution)
|
||||
.map(|vec2| self.rotation * vec2)
|
||||
.map(|vec2| vec2 + self.position);
|
||||
let positions =
|
||||
ellipse_inner(self.half_size, self.resolution).map(|vec2| self.isometry * vec2);
|
||||
self.gizmos.linestrip_2d(positions, self.color);
|
||||
}
|
||||
}
|
||||
|
@ -312,10 +323,7 @@ where
|
|||
// Radius of the sphere
|
||||
radius: f32,
|
||||
|
||||
// Rotation of the sphere around the origin in 3D space
|
||||
rotation: Quat,
|
||||
// Center position of the sphere in 3D space
|
||||
position: Vec3,
|
||||
isometry: Isometry3d,
|
||||
// Color of the sphere
|
||||
color: Color,
|
||||
|
||||
|
@ -345,21 +353,12 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let SphereBuilder {
|
||||
radius,
|
||||
position: center,
|
||||
rotation,
|
||||
color,
|
||||
resolution,
|
||||
..
|
||||
} = self;
|
||||
|
||||
// draws one great circle around each of the local axes
|
||||
Vec3::AXES.into_iter().for_each(|axis| {
|
||||
let normal = *rotation * axis;
|
||||
let axis_rotation = Isometry3d::from_rotation(Quat::from_rotation_arc(Vec3::Z, axis));
|
||||
self.gizmos
|
||||
.circle(*center, Dir3::new_unchecked(normal), *radius, *color)
|
||||
.resolution(*resolution);
|
||||
.circle(self.isometry * axis_rotation, self.radius, self.color)
|
||||
.resolution(self.resolution);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,18 @@
|
|||
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
use bevy_color::Color;
|
||||
use bevy_math::{Mat2, Mat3, Quat, Vec2, Vec3};
|
||||
use bevy_math::{Isometry2d, Isometry3d, Vec2, Vec3};
|
||||
|
||||
impl<Config> Gizmos<'_, '_, Config>
|
||||
where
|
||||
Config: GizmoConfigGroup,
|
||||
{
|
||||
/// Draw a cross in 3D at `position`.
|
||||
/// Draw a cross in 3D with the given `isometry` applied.
|
||||
///
|
||||
/// If `isometry == Isometry3d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec3::ZERO`
|
||||
/// - the `half_size`s are aligned with the `Vec3::X`, `Vec3::Y` and `Vec3::Z` axes.
|
||||
///
|
||||
/// This should be called for each frame the cross needs to be rendered.
|
||||
///
|
||||
|
@ -21,29 +26,26 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::WHITE;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.cross(Vec3::ZERO, Quat::IDENTITY, 0.5, WHITE);
|
||||
/// gizmos.cross(Isometry3d::IDENTITY, 0.5, WHITE);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
pub fn cross(
|
||||
&mut self,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
half_size: f32,
|
||||
color: impl Into<Color>,
|
||||
) {
|
||||
let axes = half_size * Mat3::from_quat(rotation);
|
||||
let local_x = axes.col(0);
|
||||
let local_y = axes.col(1);
|
||||
let local_z = axes.col(2);
|
||||
|
||||
pub fn cross(&mut self, isometry: Isometry3d, half_size: f32, color: impl Into<Color>) {
|
||||
let color: Color = color.into();
|
||||
self.line(position + local_x, position - local_x, color);
|
||||
self.line(position + local_y, position - local_y, color);
|
||||
self.line(position + local_z, position - local_z, color);
|
||||
[Vec3::X, Vec3::Y, Vec3::Z]
|
||||
.map(|axis| axis * half_size)
|
||||
.into_iter()
|
||||
.for_each(|axis| {
|
||||
self.line(isometry * axis, isometry * (-axis), color);
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw a cross in 2D (on the xy plane) at `position`.
|
||||
/// Draw a cross in 2D with the given `isometry` applied.
|
||||
///
|
||||
/// If `isometry == Isometry2d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec3::ZERO`
|
||||
/// - the `half_size`s are aligned with the `Vec3::X` and `Vec3::Y` axes.
|
||||
///
|
||||
/// This should be called for each frame the cross needs to be rendered.
|
||||
///
|
||||
|
@ -53,23 +55,17 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::WHITE;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.cross_2d(Vec2::ZERO, 0.0, 0.5, WHITE);
|
||||
/// gizmos.cross_2d(Isometry2d::IDENTITY, 0.5, WHITE);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
pub fn cross_2d(
|
||||
&mut self,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
half_size: f32,
|
||||
color: impl Into<Color>,
|
||||
) {
|
||||
let axes = half_size * Mat2::from_angle(angle);
|
||||
let local_x = axes.col(0);
|
||||
let local_y = axes.col(1);
|
||||
|
||||
pub fn cross_2d(&mut self, isometry: Isometry2d, half_size: f32, color: impl Into<Color>) {
|
||||
let color: Color = color.into();
|
||||
self.line_2d(position + local_x, position - local_x, color);
|
||||
self.line_2d(position + local_y, position - local_y, color);
|
||||
[Vec2::X, Vec2::Y]
|
||||
.map(|axis| axis * half_size)
|
||||
.into_iter()
|
||||
.for_each(|axis| {
|
||||
self.line_2d(isometry * axis, isometry * (-axis), color);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use bevy_ecs::{
|
|||
system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam},
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||
};
|
||||
use bevy_math::{Quat, Rot2, Vec2, Vec3};
|
||||
use bevy_math::{Isometry2d, Isometry3d, Vec2, Vec3};
|
||||
use bevy_transform::TransformPoint;
|
||||
use bevy_utils::default;
|
||||
|
||||
|
@ -452,7 +452,12 @@ where
|
|||
strip_colors.push(LinearRgba::NAN);
|
||||
}
|
||||
|
||||
/// Draw a wireframe rectangle in 3D.
|
||||
/// Draw a wireframe rectangle in 3D with the given `isometry` applied.
|
||||
///
|
||||
/// If `isometry == Isometry3d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec3::ZERO`
|
||||
/// - the sizes are aligned with the `Vec3::X` and `Vec3::Y` axes.
|
||||
///
|
||||
/// This should be called for each frame the rectangle needs to be rendered.
|
||||
///
|
||||
|
@ -462,16 +467,16 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::GREEN;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.rect(Vec3::ZERO, Quat::IDENTITY, Vec2::ONE, GREEN);
|
||||
/// gizmos.rect(Isometry3d::IDENTITY, Vec2::ONE, GREEN);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn rect(&mut self, position: Vec3, rotation: Quat, size: Vec2, color: impl Into<Color>) {
|
||||
pub fn rect(&mut self, isometry: Isometry3d, size: Vec2, color: impl Into<Color>) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| position + rotation * vec2.extend(0.));
|
||||
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| isometry * vec2.extend(0.));
|
||||
self.linestrip([tl, tr, br, bl, tl], color);
|
||||
}
|
||||
|
||||
|
@ -674,7 +679,12 @@ where
|
|||
self.line_gradient_2d(start, start + vector, start_color, end_color);
|
||||
}
|
||||
|
||||
/// Draw a wireframe rectangle in 2D.
|
||||
/// Draw a wireframe rectangle in 2D with the given `isometry` applied.
|
||||
///
|
||||
/// If `isometry == Isometry2d::IDENTITY` then
|
||||
///
|
||||
/// - the center is at `Vec2::ZERO`
|
||||
/// - the sizes are aligned with the `Vec2::X` and `Vec2::Y` axes.
|
||||
///
|
||||
/// This should be called for each frame the rectangle needs to be rendered.
|
||||
///
|
||||
|
@ -684,23 +694,16 @@ where
|
|||
/// # use bevy_math::prelude::*;
|
||||
/// # use bevy_color::palettes::basic::GREEN;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.rect_2d(Vec2::ZERO, 0., Vec2::ONE, GREEN);
|
||||
/// gizmos.rect_2d(Isometry2d::IDENTITY, Vec2::ONE, GREEN);
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn rect_2d(
|
||||
&mut self,
|
||||
position: Vec2,
|
||||
rotation: impl Into<Rot2>,
|
||||
size: Vec2,
|
||||
color: impl Into<Color>,
|
||||
) {
|
||||
pub fn rect_2d(&mut self, isometry: Isometry2d, size: Vec2, color: impl Into<Color>) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
let rotation: Rot2 = rotation.into();
|
||||
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| position + rotation * vec2);
|
||||
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| isometry * vec2);
|
||||
self.linestrip_2d([tl, tr, br, bl, tl], color);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
use bevy_color::Color;
|
||||
use bevy_math::{Quat, UVec2, UVec3, Vec2, Vec3, Vec3Swizzles};
|
||||
use bevy_math::Vec3Swizzles;
|
||||
use bevy_math::{Isometry2d, Isometry3d, Quat, UVec2, UVec3, Vec2, Vec3};
|
||||
|
||||
/// A builder returned by [`Gizmos::grid_3d`]
|
||||
pub struct GridBuilder3d<'a, 'w, 's, Config, Clear>
|
||||
|
@ -14,8 +15,7 @@ where
|
|||
Clear: 'static + Send + Sync,
|
||||
{
|
||||
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
spacing: Vec3,
|
||||
cell_count: UVec3,
|
||||
skew: Vec3,
|
||||
|
@ -29,8 +29,7 @@ where
|
|||
Clear: 'static + Send + Sync,
|
||||
{
|
||||
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
spacing: Vec2,
|
||||
cell_count: UVec2,
|
||||
skew: Vec2,
|
||||
|
@ -147,8 +146,7 @@ where
|
|||
fn drop(&mut self) {
|
||||
draw_grid(
|
||||
self.gizmos,
|
||||
self.position,
|
||||
self.rotation,
|
||||
self.isometry,
|
||||
self.spacing,
|
||||
self.cell_count,
|
||||
self.skew,
|
||||
|
@ -166,8 +164,7 @@ where
|
|||
fn drop(&mut self) {
|
||||
draw_grid(
|
||||
self.gizmos,
|
||||
self.position,
|
||||
self.rotation,
|
||||
self.isometry,
|
||||
self.spacing.extend(0.),
|
||||
self.cell_count.extend(0),
|
||||
self.skew.extend(0.),
|
||||
|
@ -187,8 +184,11 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `position`: The center point of the grid.
|
||||
/// - `rotation`: defines the orientation of the grid, by default we assume the grid is contained in a plane parallel to the XY plane.
|
||||
/// - `isometry` defines the translation and rotation of the grid.
|
||||
/// - the translation specifies the center of the grid
|
||||
/// - defines the orientation of the grid, by default
|
||||
/// we assume the grid is contained in a plane parallel
|
||||
/// to the XY plane
|
||||
/// - `cell_count`: defines the amount of cells in the x and y axes
|
||||
/// - `spacing`: defines the distance between cells along the x and y axes
|
||||
/// - `color`: color of the grid
|
||||
|
@ -205,8 +205,7 @@ where
|
|||
/// # use bevy_color::palettes::basic::GREEN;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.grid(
|
||||
/// Vec3::ZERO,
|
||||
/// Quat::IDENTITY,
|
||||
/// Isometry3d::IDENTITY,
|
||||
/// UVec2::new(10, 10),
|
||||
/// Vec2::splat(2.),
|
||||
/// GREEN
|
||||
|
@ -218,16 +217,14 @@ where
|
|||
/// ```
|
||||
pub fn grid(
|
||||
&mut self,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
cell_count: UVec2,
|
||||
spacing: Vec2,
|
||||
color: impl Into<Color>,
|
||||
) -> GridBuilder2d<'_, 'w, 's, Config, Clear> {
|
||||
GridBuilder2d {
|
||||
gizmos: self,
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
spacing,
|
||||
cell_count,
|
||||
skew: Vec2::ZERO,
|
||||
|
@ -242,8 +239,10 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `position`: The center point of the grid.
|
||||
/// - `rotation`: defines the orientation of the grid, by default we assume the grid is contained in a plane parallel to the XY plane.
|
||||
/// - `isometry` defines the translation and rotation of the grid.
|
||||
/// - the translation specifies the center of the grid
|
||||
/// - defines the orientation of the grid, by default
|
||||
/// we assume the grid is aligned with all axes
|
||||
/// - `cell_count`: defines the amount of cells in the x, y and z axes
|
||||
/// - `spacing`: defines the distance between cells along the x, y and z axes
|
||||
/// - `color`: color of the grid
|
||||
|
@ -260,8 +259,7 @@ where
|
|||
/// # use bevy_color::palettes::basic::GREEN;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.grid_3d(
|
||||
/// Vec3::ZERO,
|
||||
/// Quat::IDENTITY,
|
||||
/// Isometry3d::IDENTITY,
|
||||
/// UVec3::new(10, 2, 10),
|
||||
/// Vec3::splat(2.),
|
||||
/// GREEN
|
||||
|
@ -273,16 +271,14 @@ where
|
|||
/// ```
|
||||
pub fn grid_3d(
|
||||
&mut self,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
cell_count: UVec3,
|
||||
spacing: Vec3,
|
||||
color: impl Into<Color>,
|
||||
) -> GridBuilder3d<'_, 'w, 's, Config, Clear> {
|
||||
GridBuilder3d {
|
||||
gizmos: self,
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
spacing,
|
||||
cell_count,
|
||||
skew: Vec3::ZERO,
|
||||
|
@ -297,8 +293,10 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `position`: The center point of the grid.
|
||||
/// - `rotation`: defines the orientation of the grid.
|
||||
/// - `isometry` defines the translation and rotation of the grid.
|
||||
/// - the translation specifies the center of the grid
|
||||
/// - defines the orientation of the grid, by default
|
||||
/// we assume the grid is aligned with all axes
|
||||
/// - `cell_count`: defines the amount of cells in the x and y axes
|
||||
/// - `spacing`: defines the distance between cells along the x and y axes
|
||||
/// - `color`: color of the grid
|
||||
|
@ -315,8 +313,7 @@ where
|
|||
/// # use bevy_color::palettes::basic::GREEN;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.grid_2d(
|
||||
/// Vec2::ZERO,
|
||||
/// 0.0,
|
||||
/// Isometry2d::IDENTITY,
|
||||
/// UVec2::new(10, 10),
|
||||
/// Vec2::splat(1.),
|
||||
/// GREEN
|
||||
|
@ -328,16 +325,17 @@ where
|
|||
/// ```
|
||||
pub fn grid_2d(
|
||||
&mut self,
|
||||
position: Vec2,
|
||||
rotation: f32,
|
||||
isometry: Isometry2d,
|
||||
cell_count: UVec2,
|
||||
spacing: Vec2,
|
||||
color: impl Into<Color>,
|
||||
) -> GridBuilder2d<'_, 'w, 's, Config, Clear> {
|
||||
GridBuilder2d {
|
||||
gizmos: self,
|
||||
position: position.extend(0.),
|
||||
rotation: Quat::from_rotation_z(rotation),
|
||||
isometry: Isometry3d::new(
|
||||
isometry.translation.extend(0.0),
|
||||
Quat::from_rotation_z(isometry.rotation.as_radians()),
|
||||
),
|
||||
spacing,
|
||||
cell_count,
|
||||
skew: Vec2::ZERO,
|
||||
|
@ -350,8 +348,7 @@ where
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
fn draw_grid<Config, Clear>(
|
||||
gizmos: &mut Gizmos<'_, '_, Config, Clear>,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
spacing: Vec3,
|
||||
cell_count: UVec3,
|
||||
skew: Vec3,
|
||||
|
@ -428,7 +425,7 @@ fn draw_grid<Config, Clear>(
|
|||
x_lines
|
||||
.chain(y_lines)
|
||||
.chain(z_lines)
|
||||
.map(|ps| ps.map(|p| position + rotation * p))
|
||||
.map(|vec3s| vec3s.map(|vec3| isometry * vec3))
|
||||
.for_each(|[start, end]| {
|
||||
gizmos.line(start, end, color);
|
||||
});
|
||||
|
|
|
@ -19,7 +19,7 @@ use bevy_ecs::{
|
|||
};
|
||||
use bevy_math::{
|
||||
primitives::{Cone, Sphere},
|
||||
Quat, Vec3,
|
||||
Isometry3d, Quat, Vec3,
|
||||
};
|
||||
use bevy_pbr::{DirectionalLight, PointLight, SpotLight};
|
||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||
|
@ -44,13 +44,16 @@ fn point_light_gizmo(
|
|||
&Sphere {
|
||||
radius: point_light.radius,
|
||||
},
|
||||
position,
|
||||
Quat::IDENTITY,
|
||||
Isometry3d::from_translation(position),
|
||||
color,
|
||||
)
|
||||
.resolution(16);
|
||||
gizmos
|
||||
.sphere(position, Quat::IDENTITY, point_light.range, color)
|
||||
.sphere(
|
||||
Isometry3d::from_translation(position),
|
||||
point_light.range,
|
||||
color,
|
||||
)
|
||||
.resolution(32);
|
||||
}
|
||||
|
||||
|
@ -68,8 +71,7 @@ fn spot_light_gizmo(
|
|||
&Sphere {
|
||||
radius: spot_light.radius,
|
||||
},
|
||||
translation,
|
||||
Quat::IDENTITY,
|
||||
Isometry3d::from_translation(translation),
|
||||
color,
|
||||
)
|
||||
.resolution(16);
|
||||
|
@ -84,8 +86,7 @@ fn spot_light_gizmo(
|
|||
radius: spot_light.range * angle.sin(),
|
||||
height,
|
||||
},
|
||||
position,
|
||||
rotation * Quat::from_rotation_x(PI / 2.0),
|
||||
Isometry3d::new(position, rotation * Quat::from_rotation_x(PI / 2.0)),
|
||||
color,
|
||||
)
|
||||
.height_resolution(4)
|
||||
|
@ -105,8 +106,7 @@ fn spot_light_gizmo(
|
|||
.arc_3d(
|
||||
2.0 * spot_light.outer_angle,
|
||||
spot_light.range,
|
||||
translation,
|
||||
rotation * arc_rotation,
|
||||
Isometry3d::new(translation, rotation * arc_rotation),
|
||||
color,
|
||||
)
|
||||
.resolution(16);
|
||||
|
|
|
@ -10,7 +10,7 @@ use bevy_math::primitives::{
|
|||
CircularSegment, Ellipse, Line2d, Plane2d, Polygon, Polyline2d, Primitive2d, Rectangle,
|
||||
RegularPolygon, Rhombus, Segment2d, Triangle2d,
|
||||
};
|
||||
use bevy_math::{Dir2, Isometry2d, Mat2, Rot2, Vec2};
|
||||
use bevy_math::{Dir2, Isometry2d, Rot2, Vec2};
|
||||
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
|
||||
|
@ -31,8 +31,7 @@ pub trait GizmoPrimitive2d<P: Primitive2d> {
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &P,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_>;
|
||||
}
|
||||
|
@ -49,19 +48,15 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Dir2,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let direction = Mat2::from_angle(angle) * **primitive;
|
||||
|
||||
let start = position;
|
||||
let end = position + MIN_LINE_LEN * direction;
|
||||
self.arrow_2d(start, end, color);
|
||||
let start = Vec2::ZERO;
|
||||
let end = *primitive * MIN_LINE_LEN;
|
||||
self.arrow_2d(isometry * start, isometry * end, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,16 +72,17 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Arc2d,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let start_iso = isometry * Isometry2d::from_rotation(Rot2::radians(-primitive.half_angle));
|
||||
|
||||
self.arc_2d(
|
||||
Isometry2d::new(position, Rot2::radians(angle - primitive.half_angle)),
|
||||
start_iso,
|
||||
primitive.half_angle * 2.0,
|
||||
primitive.radius,
|
||||
color,
|
||||
|
@ -106,11 +102,10 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Circle,
|
||||
position: Vec2,
|
||||
_angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
self.circle_2d(position, primitive.radius, color)
|
||||
self.circle_2d(isometry, primitive.radius, color)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,8 +121,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &CircularSector,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -136,20 +130,21 @@ where
|
|||
|
||||
let color = color.into();
|
||||
|
||||
let start_iso =
|
||||
isometry * Isometry2d::from_rotation(Rot2::radians(-primitive.arc.half_angle));
|
||||
let end_iso = isometry * Isometry2d::from_rotation(Rot2::radians(primitive.arc.half_angle));
|
||||
|
||||
// we need to draw the arc part of the sector, and the two lines connecting the arc and the center
|
||||
self.arc_2d(
|
||||
Isometry2d::new(position, Rot2::radians(angle - primitive.arc.half_angle)),
|
||||
start_iso,
|
||||
primitive.arc.half_angle * 2.0,
|
||||
primitive.arc.radius,
|
||||
color,
|
||||
);
|
||||
|
||||
let start = position
|
||||
+ primitive.arc.radius * Mat2::from_angle(angle - primitive.arc.half_angle) * Vec2::Y;
|
||||
let end = position
|
||||
+ primitive.arc.radius * Mat2::from_angle(angle + primitive.arc.half_angle) * Vec2::Y;
|
||||
self.line_2d(position, start, color);
|
||||
self.line_2d(position, end, color);
|
||||
let end_position = primitive.arc.radius * Vec2::Y;
|
||||
self.line_2d(isometry * Vec2::ZERO, start_iso * end_position, color);
|
||||
self.line_2d(isometry * Vec2::ZERO, end_iso * end_position, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,8 +160,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &CircularSegment,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -175,19 +169,20 @@ where
|
|||
|
||||
let color = color.into();
|
||||
|
||||
let start_iso =
|
||||
isometry * Isometry2d::from_rotation(Rot2::radians(-primitive.arc.half_angle));
|
||||
let end_iso = isometry * Isometry2d::from_rotation(Rot2::radians(primitive.arc.half_angle));
|
||||
|
||||
// we need to draw the arc part of the segment, and the line connecting the two ends
|
||||
self.arc_2d(
|
||||
Isometry2d::new(position, Rot2::radians(angle - primitive.arc.half_angle)),
|
||||
start_iso,
|
||||
primitive.arc.half_angle * 2.0,
|
||||
primitive.arc.radius,
|
||||
color,
|
||||
);
|
||||
|
||||
let start = position
|
||||
+ primitive.arc.radius * Mat2::from_angle(angle - primitive.arc.half_angle) * Vec2::Y;
|
||||
let end = position
|
||||
+ primitive.arc.radius * Mat2::from_angle(angle + primitive.arc.half_angle) * Vec2::Y;
|
||||
self.line_2d(end, start, color);
|
||||
let position = primitive.arc.radius * Vec2::Y;
|
||||
self.line_2d(start_iso * position, end_iso * position, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,11 +198,10 @@ where
|
|||
fn primitive_2d<'a>(
|
||||
&mut self,
|
||||
primitive: &Ellipse,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
self.ellipse_2d(position, angle, primitive.half_size, color)
|
||||
self.ellipse_2d(isometry, primitive.half_size, color)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +214,7 @@ where
|
|||
Clear: 'static + Send + Sync,
|
||||
{
|
||||
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
||||
position: Vec2,
|
||||
isometry: Isometry2d,
|
||||
inner_radius: f32,
|
||||
outer_radius: f32,
|
||||
color: Color,
|
||||
|
@ -263,13 +257,12 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Annulus,
|
||||
position: Vec2,
|
||||
_angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
Annulus2dBuilder {
|
||||
gizmos: self,
|
||||
position,
|
||||
isometry,
|
||||
inner_radius: primitive.inner_circle.radius,
|
||||
outer_radius: primitive.outer_circle.radius,
|
||||
color: color.into(),
|
||||
|
@ -291,7 +284,7 @@ where
|
|||
|
||||
let Annulus2dBuilder {
|
||||
gizmos,
|
||||
position,
|
||||
isometry,
|
||||
inner_radius,
|
||||
outer_radius,
|
||||
inner_resolution,
|
||||
|
@ -301,10 +294,10 @@ where
|
|||
} = self;
|
||||
|
||||
gizmos
|
||||
.circle_2d(*position, *outer_radius, *color)
|
||||
.circle_2d(*isometry, *outer_radius, *color)
|
||||
.resolution(*outer_resolution);
|
||||
gizmos
|
||||
.circle_2d(*position, *inner_radius, *color)
|
||||
.circle_2d(*isometry, *inner_radius, *color)
|
||||
.resolution(*inner_resolution);
|
||||
}
|
||||
}
|
||||
|
@ -321,8 +314,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Rhombus,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -335,7 +327,7 @@ where
|
|||
primitive.half_diagonals.y * sign_y,
|
||||
)
|
||||
});
|
||||
let positions = [a, b, c, d, a].map(rotate_then_translate_2d(angle, position));
|
||||
let positions = [a, b, c, d, a].map(|vec2| isometry * vec2);
|
||||
self.linestrip_2d(positions, color);
|
||||
}
|
||||
}
|
||||
|
@ -352,8 +344,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Capsule2d,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
let polymorphic_color: Color = color.into();
|
||||
|
@ -377,14 +368,14 @@ where
|
|||
let scaling = Vec2::X * primitive.radius + Vec2::Y * primitive.half_length;
|
||||
reference_point * scaling
|
||||
})
|
||||
.map(rotate_then_translate_2d(angle, position));
|
||||
.map(|vec2| isometry * vec2);
|
||||
|
||||
// draw left and right side of capsule "rectangle"
|
||||
self.line_2d(bottom_left, top_left, polymorphic_color);
|
||||
self.line_2d(bottom_right, top_right, polymorphic_color);
|
||||
|
||||
let start_angle_top = angle - FRAC_PI_2;
|
||||
let start_angle_bottom = angle + FRAC_PI_2;
|
||||
let start_angle_top = isometry.rotation.as_radians() - FRAC_PI_2;
|
||||
let start_angle_bottom = isometry.rotation.as_radians() + FRAC_PI_2;
|
||||
|
||||
// draw arcs
|
||||
self.arc_2d(
|
||||
|
@ -414,9 +405,8 @@ where
|
|||
|
||||
direction: Dir2, // Direction of the line
|
||||
|
||||
position: Vec2, // position of the center of the line
|
||||
rotation: Mat2, // rotation of the line
|
||||
color: Color, // color of the line
|
||||
isometry: Isometry2d,
|
||||
color: Color, // color of the line
|
||||
|
||||
draw_arrow: bool, // decides whether to indicate the direction of the line with an arrow
|
||||
}
|
||||
|
@ -443,15 +433,13 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Line2d,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
Line2dBuilder {
|
||||
gizmos: self,
|
||||
direction: primitive.direction,
|
||||
position,
|
||||
rotation: Mat2::from_angle(angle),
|
||||
isometry,
|
||||
color: color.into(),
|
||||
draw_arrow: false,
|
||||
}
|
||||
|
@ -468,22 +456,20 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let direction = self.rotation * *self.direction;
|
||||
|
||||
let [start, end] = [1.0, -1.0]
|
||||
.map(|sign| sign * INFINITE_LEN)
|
||||
// offset the line from the origin infinitely into the given direction
|
||||
.map(|length| direction * length)
|
||||
// translate the line to the given position
|
||||
.map(|offset| self.position + offset);
|
||||
.map(|length| self.direction * length)
|
||||
// transform the line with the given isometry
|
||||
.map(|offset| self.isometry * offset);
|
||||
|
||||
self.gizmos.line_2d(start, end, self.color);
|
||||
|
||||
// optionally draw an arrow head at the center of the line
|
||||
if self.draw_arrow {
|
||||
self.gizmos.arrow_2d(
|
||||
self.position - direction * MIN_LINE_LEN,
|
||||
self.position,
|
||||
self.isometry * (-self.direction * MIN_LINE_LEN),
|
||||
self.isometry * Vec2::ZERO,
|
||||
self.color,
|
||||
);
|
||||
}
|
||||
|
@ -502,8 +488,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Plane2d,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
let polymorphic_color: Color = color.into();
|
||||
|
@ -511,8 +496,6 @@ where
|
|||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
let rotation = Mat2::from_angle(angle);
|
||||
|
||||
// draw normal of the plane (orthogonal to the plane itself)
|
||||
let normal = primitive.normal;
|
||||
let normal_segment = Segment2d {
|
||||
|
@ -522,22 +505,21 @@ where
|
|||
self.primitive_2d(
|
||||
&normal_segment,
|
||||
// offset the normal so it starts on the plane line
|
||||
position + HALF_MIN_LINE_LEN * rotation * *normal,
|
||||
angle,
|
||||
Isometry2d::new(isometry * (HALF_MIN_LINE_LEN * normal), isometry.rotation),
|
||||
polymorphic_color,
|
||||
)
|
||||
.draw_arrow(true);
|
||||
|
||||
// draw the plane line
|
||||
let direction = Dir2::new_unchecked(-normal.perp());
|
||||
self.primitive_2d(&Line2d { direction }, position, angle, polymorphic_color)
|
||||
self.primitive_2d(&Line2d { direction }, isometry, polymorphic_color)
|
||||
.draw_arrow(false);
|
||||
|
||||
// draw an arrow such that the normal is always left side of the plane with respect to the
|
||||
// planes direction. This is to follow the "counter-clockwise" convention
|
||||
self.arrow_2d(
|
||||
position,
|
||||
position + MIN_LINE_LEN * (rotation * *direction),
|
||||
isometry * Vec2::ZERO,
|
||||
isometry * (MIN_LINE_LEN * direction),
|
||||
polymorphic_color,
|
||||
);
|
||||
}
|
||||
|
@ -556,9 +538,8 @@ where
|
|||
direction: Dir2, // Direction of the line segment
|
||||
half_length: f32, // Half-length of the line segment
|
||||
|
||||
position: Vec2, // position of the center of the line segment
|
||||
rotation: Mat2, // rotation of the line segment
|
||||
color: Color, // color of the line segment
|
||||
isometry: Isometry2d, // isometric transformation of the line segment
|
||||
color: Color, // color of the line segment
|
||||
|
||||
draw_arrow: bool, // decides whether to draw just a line or an arrow
|
||||
}
|
||||
|
@ -585,8 +566,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Segment2d,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
Segment2dBuilder {
|
||||
|
@ -594,8 +574,7 @@ where
|
|||
direction: primitive.direction,
|
||||
half_length: primitive.half_length,
|
||||
|
||||
position,
|
||||
rotation: Mat2::from_angle(angle),
|
||||
isometry,
|
||||
color: color.into(),
|
||||
|
||||
draw_arrow: Default::default(),
|
||||
|
@ -613,9 +592,9 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let direction = self.rotation * *self.direction;
|
||||
let start = self.position - direction * self.half_length;
|
||||
let end = self.position + direction * self.half_length;
|
||||
let direction = self.direction * self.half_length;
|
||||
let start = self.isometry * (-direction);
|
||||
let end = self.isometry * direction;
|
||||
|
||||
if self.draw_arrow {
|
||||
self.gizmos.arrow_2d(start, end, self.color);
|
||||
|
@ -638,8 +617,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Polyline2d<N>,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -651,7 +629,7 @@ where
|
|||
.vertices
|
||||
.iter()
|
||||
.copied()
|
||||
.map(rotate_then_translate_2d(angle, position)),
|
||||
.map(|vec2| isometry * vec2),
|
||||
color,
|
||||
);
|
||||
}
|
||||
|
@ -669,8 +647,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &BoxedPolyline2d,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -682,7 +659,7 @@ where
|
|||
.vertices
|
||||
.iter()
|
||||
.copied()
|
||||
.map(rotate_then_translate_2d(angle, position)),
|
||||
.map(|vec2| isometry * vec2),
|
||||
color,
|
||||
);
|
||||
}
|
||||
|
@ -700,15 +677,14 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Triangle2d,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
let [a, b, c] = primitive.vertices;
|
||||
let positions = [a, b, c, a].map(rotate_then_translate_2d(angle, position));
|
||||
let positions = [a, b, c, a].map(|vec2| isometry * vec2);
|
||||
self.linestrip_2d(positions, color);
|
||||
}
|
||||
}
|
||||
|
@ -725,8 +701,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Rectangle,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -740,7 +715,7 @@ where
|
|||
primitive.half_size.y * sign_y,
|
||||
)
|
||||
});
|
||||
let positions = [a, b, c, d, a].map(rotate_then_translate_2d(angle, position));
|
||||
let positions = [a, b, c, d, a].map(|vec2| isometry * vec2);
|
||||
self.linestrip_2d(positions, color);
|
||||
}
|
||||
}
|
||||
|
@ -758,8 +733,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &Polygon<N>,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -781,7 +755,7 @@ where
|
|||
.iter()
|
||||
.copied()
|
||||
.chain(closing_point)
|
||||
.map(rotate_then_translate_2d(angle, position)),
|
||||
.map(|vec2| isometry * vec2),
|
||||
color,
|
||||
);
|
||||
}
|
||||
|
@ -799,8 +773,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &BoxedPolygon,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -820,7 +793,7 @@ where
|
|||
.iter()
|
||||
.copied()
|
||||
.chain(closing_point)
|
||||
.map(rotate_then_translate_2d(angle, position)),
|
||||
.map(|vec2| isometry * vec2),
|
||||
color,
|
||||
);
|
||||
}
|
||||
|
@ -838,8 +811,7 @@ where
|
|||
fn primitive_2d(
|
||||
&mut self,
|
||||
primitive: &RegularPolygon,
|
||||
position: Vec2,
|
||||
angle: f32,
|
||||
isometry: Isometry2d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -847,8 +819,8 @@ where
|
|||
}
|
||||
|
||||
let points = (0..=primitive.sides)
|
||||
.map(|p| single_circle_coordinate(primitive.circumcircle.radius, primitive.sides, p))
|
||||
.map(rotate_then_translate_2d(angle, position));
|
||||
.map(|n| single_circle_coordinate(primitive.circumcircle.radius, primitive.sides, n))
|
||||
.map(|vec2| isometry * vec2);
|
||||
self.linestrip_2d(points, color);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
//! A module for rendering each of the 3D [`bevy_math::primitives`] with [`Gizmos`].
|
||||
|
||||
use super::helpers::*;
|
||||
use std::f32::consts::{FRAC_PI_2, PI, TAU};
|
||||
use std::f32::consts::TAU;
|
||||
|
||||
use bevy_color::Color;
|
||||
use bevy_math::primitives::{
|
||||
BoxedPolyline3d, Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, Line3d, Plane3d,
|
||||
Polyline3d, Primitive3d, Segment3d, Sphere, Tetrahedron, Torus, Triangle3d,
|
||||
};
|
||||
use bevy_math::{Dir3, Quat, Vec3};
|
||||
use bevy_math::{Dir3, Isometry3d, Quat, Vec3};
|
||||
|
||||
use crate::circles::SphereBuilder;
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
|
@ -28,8 +28,7 @@ pub trait GizmoPrimitive3d<P: Primitive3d> {
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &P,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_>;
|
||||
}
|
||||
|
@ -46,11 +45,12 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Dir3,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
self.arrow(position, position + (rotation * **primitive), color);
|
||||
let start = Vec3::ZERO;
|
||||
let end = primitive.as_vec3();
|
||||
self.arrow(isometry * start, isometry * end, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,11 +66,10 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Sphere,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
self.sphere(position, rotation, primitive.radius, color)
|
||||
self.sphere(isometry, primitive.radius, color)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,10 +86,7 @@ where
|
|||
// direction of the normal orthogonal to the plane
|
||||
normal: Dir3,
|
||||
|
||||
// Rotation of the plane around the origin in 3D space
|
||||
rotation: Quat,
|
||||
// Center position of the plane in 3D space
|
||||
position: Vec3,
|
||||
isometry: Isometry3d,
|
||||
// Color of the plane
|
||||
color: Color,
|
||||
|
||||
|
@ -136,15 +132,13 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Plane3d,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
Plane3dBuilder {
|
||||
gizmos: self,
|
||||
normal: primitive.normal,
|
||||
rotation,
|
||||
position,
|
||||
isometry,
|
||||
color: color.into(),
|
||||
axis_count: 4,
|
||||
segment_count: 3,
|
||||
|
@ -164,37 +158,33 @@ where
|
|||
}
|
||||
|
||||
// draws the normal
|
||||
let normal = self.rotation * *self.normal;
|
||||
self.gizmos
|
||||
.primitive_3d(&self.normal, self.position, self.rotation, self.color);
|
||||
let normals_normal = self.rotation * self.normal.any_orthonormal_vector();
|
||||
.primitive_3d(&self.normal, self.isometry, self.color);
|
||||
|
||||
// draws the axes
|
||||
// get rotation for each direction
|
||||
let normals_normal = self.normal.any_orthonormal_vector();
|
||||
(0..self.axis_count)
|
||||
.map(|i| i as f32 * (1.0 / self.axis_count as f32) * TAU)
|
||||
.map(|angle| Quat::from_axis_angle(normal, angle))
|
||||
.for_each(|quat| {
|
||||
let axis_direction = quat * normals_normal;
|
||||
let direction = Dir3::new_unchecked(axis_direction);
|
||||
|
||||
.map(|angle| Quat::from_axis_angle(self.normal.as_vec3(), angle))
|
||||
.flat_map(|quat| {
|
||||
let segment_length = self.segment_length;
|
||||
let isometry = self.isometry;
|
||||
// for each axis draw dotted line
|
||||
(0..)
|
||||
.filter(|i| i % 2 != 0)
|
||||
.map(|percent| (percent as f32 + 0.5) * self.segment_length * axis_direction)
|
||||
.map(|position| position + self.position)
|
||||
.take(self.segment_count as usize)
|
||||
.for_each(|position| {
|
||||
self.gizmos.primitive_3d(
|
||||
&Segment3d {
|
||||
direction,
|
||||
half_length: self.segment_length * 0.5,
|
||||
},
|
||||
position,
|
||||
Quat::IDENTITY,
|
||||
self.color,
|
||||
);
|
||||
});
|
||||
.map(|i| [i, i + 1])
|
||||
.map(move |percents| {
|
||||
percents
|
||||
.map(|percent| percent as f32 + 0.5)
|
||||
.map(|percent| percent * segment_length * normals_normal)
|
||||
.map(|vec3| quat * vec3)
|
||||
.map(|vec3| isometry * vec3)
|
||||
})
|
||||
})
|
||||
.for_each(|[start, end]| {
|
||||
self.gizmos.line(start, end, self.color);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -211,8 +201,7 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Line3d,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -220,13 +209,13 @@ where
|
|||
}
|
||||
|
||||
let color = color.into();
|
||||
let direction = rotation * *primitive.direction;
|
||||
self.arrow(position, position + direction, color);
|
||||
let direction = primitive.direction.as_vec3();
|
||||
self.arrow(isometry * Vec3::ZERO, isometry * direction, color);
|
||||
|
||||
let [start, end] = [1.0, -1.0]
|
||||
.map(|sign| sign * INFINITE_LEN)
|
||||
.map(|length| direction * length)
|
||||
.map(|offset| position + offset);
|
||||
.map(|length| primitive.direction * length)
|
||||
.map(|offset| isometry * offset);
|
||||
self.line(start, end, color);
|
||||
}
|
||||
}
|
||||
|
@ -243,18 +232,15 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Segment3d,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let direction = rotation * *primitive.direction;
|
||||
let start = position - direction * primitive.half_length;
|
||||
let end = position + direction * primitive.half_length;
|
||||
self.line(start, end, color);
|
||||
let direction = primitive.direction.as_vec3();
|
||||
self.line(isometry * direction, isometry * (-direction), color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,20 +257,14 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Polyline3d<N>,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
self.linestrip(
|
||||
primitive
|
||||
.vertices
|
||||
.map(rotate_then_translate_3d(rotation, position)),
|
||||
color,
|
||||
);
|
||||
self.linestrip(primitive.vertices.map(|vec3| isometry * vec3), color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,8 +280,7 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &BoxedPolyline3d,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -313,7 +292,7 @@ where
|
|||
.vertices
|
||||
.iter()
|
||||
.copied()
|
||||
.map(rotate_then_translate_3d(rotation, position)),
|
||||
.map(|vec3| isometry * vec3),
|
||||
color,
|
||||
);
|
||||
}
|
||||
|
@ -331,8 +310,7 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Triangle3d,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
|
@ -340,10 +318,7 @@ where
|
|||
}
|
||||
|
||||
let [a, b, c] = primitive.vertices;
|
||||
self.linestrip(
|
||||
[a, b, c, a].map(rotate_then_translate_3d(rotation, position)),
|
||||
color,
|
||||
);
|
||||
self.linestrip([a, b, c, a].map(|vec3| isometry * vec3), color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,16 +334,13 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Cuboid,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let [half_extend_x, half_extend_y, half_extend_z] = primitive.half_size.to_array();
|
||||
|
||||
// transform the points from the reference unit cube to the cuboid coords
|
||||
let vertices @ [a, b, c, d, e, f, g, h] = [
|
||||
[1.0, 1.0, 1.0],
|
||||
|
@ -380,8 +352,9 @@ where
|
|||
[-1.0, -1.0, -1.0],
|
||||
[1.0, -1.0, -1.0],
|
||||
]
|
||||
.map(|[sx, sy, sz]| Vec3::new(sx * half_extend_x, sy * half_extend_y, sz * half_extend_z))
|
||||
.map(rotate_then_translate_3d(rotation, position));
|
||||
.map(Vec3::from)
|
||||
.map(|vec3| vec3 * primitive.half_size)
|
||||
.map(|vec3| isometry * vec3);
|
||||
|
||||
// lines for the upper rectangle of the cuboid
|
||||
let upper = [a, b, c, d]
|
||||
|
@ -421,12 +394,7 @@ where
|
|||
// Half height of the cylinder
|
||||
half_height: f32,
|
||||
|
||||
// Center position of the cylinder
|
||||
position: Vec3,
|
||||
// Rotation of the cylinder
|
||||
//
|
||||
// default orientation is: the cylinder is aligned with `Vec3::Y` axis
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
// Color of the cylinder
|
||||
color: Color,
|
||||
|
||||
|
@ -456,16 +424,14 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Cylinder,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
Cylinder3dBuilder {
|
||||
gizmos: self,
|
||||
radius: primitive.radius,
|
||||
half_height: primitive.half_height,
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
color: color.into(),
|
||||
resolution: DEFAULT_RESOLUTION,
|
||||
}
|
||||
|
@ -482,37 +448,17 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let Cylinder3dBuilder {
|
||||
gizmos,
|
||||
radius,
|
||||
half_height,
|
||||
position,
|
||||
rotation,
|
||||
color,
|
||||
resolution,
|
||||
} = self;
|
||||
|
||||
let normal = Dir3::new_unchecked(*rotation * Vec3::Y);
|
||||
let up = normal.as_vec3() * *half_height;
|
||||
|
||||
// draw upper and lower circle of the cylinder
|
||||
[-1.0, 1.0].into_iter().for_each(|sign| {
|
||||
gizmos
|
||||
.circle(*position + sign * up, normal, *radius, *color)
|
||||
.resolution(*resolution);
|
||||
});
|
||||
|
||||
// draw lines connecting the two cylinder circles
|
||||
[Vec3::NEG_X, Vec3::NEG_Z, Vec3::X, Vec3::Z]
|
||||
.into_iter()
|
||||
.for_each(|axis| {
|
||||
let axis = *rotation * axis;
|
||||
gizmos.line(
|
||||
*position + up + axis * *radius,
|
||||
*position - up + axis * *radius,
|
||||
*color,
|
||||
);
|
||||
});
|
||||
self.gizmos
|
||||
.primitive_3d(
|
||||
&ConicalFrustum {
|
||||
radius_top: self.radius,
|
||||
radius_bottom: self.radius,
|
||||
height: self.half_height * 2.0,
|
||||
},
|
||||
self.isometry,
|
||||
self.color,
|
||||
)
|
||||
.resolution(self.resolution);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -531,12 +477,7 @@ where
|
|||
// Half length of the capsule
|
||||
half_length: f32,
|
||||
|
||||
// Center position of the capsule
|
||||
position: Vec3,
|
||||
// Rotation of the capsule
|
||||
//
|
||||
// default orientation is: the capsule is aligned with `Vec3::Y` axis
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
// Color of the capsule
|
||||
color: Color,
|
||||
|
||||
|
@ -566,16 +507,14 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Capsule3d,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
Capsule3dBuilder {
|
||||
gizmos: self,
|
||||
radius: primitive.radius,
|
||||
half_length: primitive.half_length,
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
color: color.into(),
|
||||
resolution: DEFAULT_RESOLUTION,
|
||||
}
|
||||
|
@ -592,66 +531,39 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let Capsule3dBuilder {
|
||||
gizmos,
|
||||
radius,
|
||||
half_length,
|
||||
position,
|
||||
rotation,
|
||||
color,
|
||||
resolution,
|
||||
} = self;
|
||||
let [upper_apex, lower_apex] = [-1.0, 1.0]
|
||||
.map(|sign| Vec3::Y * sign * (self.half_length + self.radius))
|
||||
.map(|vec3| self.isometry * vec3);
|
||||
let [upper_center, lower_center] = [-1.0, 1.0]
|
||||
.map(|sign| Vec3::Y * sign * self.half_length)
|
||||
.map(|vec3| self.isometry * vec3);
|
||||
let [upper_points, lower_points] = [-1.0, 1.0]
|
||||
.map(|sign| Vec3::Y * sign * self.half_length)
|
||||
.map(|vec3| {
|
||||
circle_coordinates_closed(self.radius, self.resolution)
|
||||
.map(|vec2| Vec3::new(vec2.x, 0.0, vec2.y) + vec3)
|
||||
.map(|vec3| self.isometry * vec3)
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
// Draw the circles at the top and bottom of the cylinder
|
||||
let y_offset = *rotation * Vec3::Y;
|
||||
gizmos
|
||||
.circle(
|
||||
*position + y_offset * *half_length,
|
||||
Dir3::new_unchecked(y_offset),
|
||||
*radius,
|
||||
*color,
|
||||
)
|
||||
.resolution(*resolution);
|
||||
gizmos
|
||||
.circle(
|
||||
*position - y_offset * *half_length,
|
||||
Dir3::new_unchecked(y_offset),
|
||||
*radius,
|
||||
*color,
|
||||
)
|
||||
.resolution(*resolution);
|
||||
let y_offset = y_offset * *half_length;
|
||||
upper_points.iter().skip(1).copied().for_each(|start| {
|
||||
self.gizmos
|
||||
.short_arc_3d_between(upper_center, start, upper_apex, self.color);
|
||||
});
|
||||
lower_points.iter().skip(1).copied().for_each(|start| {
|
||||
self.gizmos
|
||||
.short_arc_3d_between(lower_center, start, lower_apex, self.color);
|
||||
});
|
||||
|
||||
// Draw the vertical lines and the cap semicircles
|
||||
[Vec3::X, Vec3::Z].into_iter().for_each(|axis| {
|
||||
let normal = *rotation * axis;
|
||||
let upper_lines = upper_points.windows(2).map(|win| (win[0], win[1]));
|
||||
let lower_lines = lower_points.windows(2).map(|win| (win[0], win[1]));
|
||||
upper_lines.chain(lower_lines).for_each(|(start, end)| {
|
||||
self.gizmos.line(start, end, self.color);
|
||||
});
|
||||
|
||||
gizmos.line(
|
||||
*position + normal * *radius + y_offset,
|
||||
*position + normal * *radius - y_offset,
|
||||
*color,
|
||||
);
|
||||
gizmos.line(
|
||||
*position - normal * *radius + y_offset,
|
||||
*position - normal * *radius - y_offset,
|
||||
*color,
|
||||
);
|
||||
|
||||
let rotation = *rotation
|
||||
* Quat::from_euler(bevy_math::EulerRot::ZYX, 0., axis.z * FRAC_PI_2, FRAC_PI_2);
|
||||
|
||||
gizmos
|
||||
.arc_3d(PI, *radius, *position + y_offset, rotation, *color)
|
||||
.resolution(*resolution / 2);
|
||||
gizmos
|
||||
.arc_3d(
|
||||
PI,
|
||||
*radius,
|
||||
*position - y_offset,
|
||||
rotation * Quat::from_rotation_y(PI),
|
||||
*color,
|
||||
)
|
||||
.resolution(*resolution / 2);
|
||||
let connection_lines = upper_points.into_iter().zip(lower_points).skip(1);
|
||||
connection_lines.for_each(|(start, end)| {
|
||||
self.gizmos.line(start, end, self.color);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -671,12 +583,7 @@ where
|
|||
// Height of the cone
|
||||
height: f32,
|
||||
|
||||
// Center of the cone, half-way between the tip and the base
|
||||
position: Vec3,
|
||||
// Rotation of the cone
|
||||
//
|
||||
// default orientation is: cone base normal is aligned with the `Vec3::Y` axis
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
// Color of the cone
|
||||
color: Color,
|
||||
|
||||
|
@ -728,16 +635,14 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Cone,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
Cone3dBuilder {
|
||||
gizmos: self,
|
||||
radius: primitive.radius,
|
||||
height: primitive.height,
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
color: color.into(),
|
||||
base_resolution: DEFAULT_RESOLUTION,
|
||||
height_resolution: DEFAULT_RESOLUTION,
|
||||
|
@ -755,37 +660,29 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let Cone3dBuilder {
|
||||
gizmos,
|
||||
radius,
|
||||
height,
|
||||
position,
|
||||
rotation,
|
||||
color,
|
||||
base_resolution,
|
||||
height_resolution,
|
||||
} = self;
|
||||
let half_height = self.height * 0.5;
|
||||
let apex = self.isometry * (Vec3::Y * half_height);
|
||||
let circle_center = half_height * Vec3::NEG_Y;
|
||||
let circle_coords = circle_coordinates_closed(self.radius, self.height_resolution)
|
||||
.map(|vec2| Vec3::new(vec2.x, 0.0, vec2.y) + circle_center)
|
||||
.map(|vec3| self.isometry * vec3)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let half_height = *height * 0.5;
|
||||
// connections to apex
|
||||
circle_coords
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|vec3| (*vec3, apex))
|
||||
.for_each(|(start, end)| {
|
||||
self.gizmos.line(start, end, self.color);
|
||||
});
|
||||
|
||||
// draw the base circle of the cone
|
||||
draw_circle_3d(
|
||||
gizmos,
|
||||
*radius,
|
||||
*base_resolution,
|
||||
*rotation,
|
||||
*position - *rotation * Vec3::Y * half_height,
|
||||
*color,
|
||||
);
|
||||
|
||||
// connect the base circle with the tip of the cone
|
||||
let end = Vec3::Y * half_height;
|
||||
circle_coordinates(*radius, *height_resolution)
|
||||
.map(|p| Vec3::new(p.x, -half_height, p.y))
|
||||
.map(move |p| [p, end])
|
||||
.map(|ps| ps.map(rotate_then_translate_3d(*rotation, *position)))
|
||||
.for_each(|[start, end]| {
|
||||
gizmos.line(start, end, *color);
|
||||
// base circle
|
||||
circle_coords
|
||||
.windows(2)
|
||||
.map(|win| (win[0], win[1]))
|
||||
.for_each(|(start, end)| {
|
||||
self.gizmos.line(start, end, self.color);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -807,12 +704,7 @@ where
|
|||
// Height of the conical frustum
|
||||
height: f32,
|
||||
|
||||
// Center of conical frustum, half-way between the top and the bottom
|
||||
position: Vec3,
|
||||
// Rotation of the conical frustum
|
||||
//
|
||||
// default orientation is: conical frustum base shape normals are aligned with `Vec3::Y` axis
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
// Color of the conical frustum
|
||||
color: Color,
|
||||
|
||||
|
@ -842,8 +734,7 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &ConicalFrustum,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
ConicalFrustum3dBuilder {
|
||||
|
@ -851,8 +742,7 @@ where
|
|||
radius_top: primitive.radius_top,
|
||||
radius_bottom: primitive.radius_bottom,
|
||||
height: primitive.height,
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
color: color.into(),
|
||||
resolution: DEFAULT_RESOLUTION,
|
||||
}
|
||||
|
@ -869,46 +759,26 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let ConicalFrustum3dBuilder {
|
||||
gizmos,
|
||||
radius_top,
|
||||
radius_bottom,
|
||||
height,
|
||||
position,
|
||||
rotation,
|
||||
color,
|
||||
resolution,
|
||||
} = self;
|
||||
|
||||
let half_height = *height * 0.5;
|
||||
let normal = *rotation * Vec3::Y;
|
||||
|
||||
// draw the two circles of the conical frustum
|
||||
[(*radius_top, half_height), (*radius_bottom, -half_height)]
|
||||
.into_iter()
|
||||
.for_each(|(radius, height)| {
|
||||
draw_circle_3d(
|
||||
gizmos,
|
||||
radius,
|
||||
*resolution,
|
||||
*rotation,
|
||||
*position + height * normal,
|
||||
*color,
|
||||
);
|
||||
let half_height = self.height * 0.5;
|
||||
let [upper_points, lower_points] = [(-1.0, self.radius_bottom), (1.0, self.radius_top)]
|
||||
.map(|(sign, radius)| {
|
||||
let translation = Vec3::Y * sign * half_height;
|
||||
circle_coordinates_closed(radius, self.resolution)
|
||||
.map(|vec2| Vec3::new(vec2.x, 0.0, vec2.y) + translation)
|
||||
.map(|vec3| self.isometry * vec3)
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
// connect the two circles of the conical frustum
|
||||
circle_coordinates(*radius_top, *resolution)
|
||||
.map(move |p| Vec3::new(p.x, half_height, p.y))
|
||||
.zip(
|
||||
circle_coordinates(*radius_bottom, *resolution)
|
||||
.map(|p| Vec3::new(p.x, -half_height, p.y)),
|
||||
)
|
||||
.map(|(start, end)| [start, end])
|
||||
.map(|ps| ps.map(rotate_then_translate_3d(*rotation, *position)))
|
||||
.for_each(|[start, end]| {
|
||||
gizmos.line(start, end, *color);
|
||||
});
|
||||
let upper_lines = upper_points.windows(2).map(|win| (win[0], win[1]));
|
||||
let lower_lines = lower_points.windows(2).map(|win| (win[0], win[1]));
|
||||
upper_lines.chain(lower_lines).for_each(|(start, end)| {
|
||||
self.gizmos.line(start, end, self.color);
|
||||
});
|
||||
|
||||
let connection_lines = upper_points.into_iter().zip(lower_points).skip(1);
|
||||
connection_lines.for_each(|(start, end)| {
|
||||
self.gizmos.line(start, end, self.color);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -927,12 +797,7 @@ where
|
|||
// Radius of the major circle (ring)
|
||||
major_radius: f32,
|
||||
|
||||
// Center of the torus
|
||||
position: Vec3,
|
||||
// Rotation of the conical frustum
|
||||
//
|
||||
// default orientation is: major circle normal is aligned with `Vec3::Y` axis
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
// Color of the torus
|
||||
color: Color,
|
||||
|
||||
|
@ -970,16 +835,14 @@ where
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Torus,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
Torus3dBuilder {
|
||||
gizmos: self,
|
||||
minor_radius: primitive.minor_radius,
|
||||
major_radius: primitive.major_radius,
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
color: color.into(),
|
||||
minor_resolution: DEFAULT_RESOLUTION,
|
||||
major_resolution: DEFAULT_RESOLUTION,
|
||||
|
@ -997,62 +860,42 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let Torus3dBuilder {
|
||||
gizmos,
|
||||
minor_radius,
|
||||
major_radius,
|
||||
position,
|
||||
rotation,
|
||||
color,
|
||||
minor_resolution,
|
||||
major_resolution,
|
||||
} = self;
|
||||
|
||||
let normal = *rotation * Vec3::Y;
|
||||
|
||||
// draw 4 circles with major_radius
|
||||
[
|
||||
(*major_radius - *minor_radius, 0.0),
|
||||
(*major_radius + *minor_radius, 0.0),
|
||||
(*major_radius, *minor_radius),
|
||||
(*major_radius, -*minor_radius),
|
||||
let [inner, outer, top, bottom] = [
|
||||
(self.major_radius - self.minor_radius, 0.0),
|
||||
(self.major_radius + self.minor_radius, 0.0),
|
||||
(self.major_radius, self.minor_radius),
|
||||
(self.major_radius, -self.minor_radius),
|
||||
]
|
||||
.into_iter()
|
||||
.for_each(|(radius, height)| {
|
||||
draw_circle_3d(
|
||||
gizmos,
|
||||
radius,
|
||||
*major_resolution,
|
||||
*rotation,
|
||||
*position + height * normal,
|
||||
*color,
|
||||
);
|
||||
.map(|(radius, height)| {
|
||||
let translation = height * Vec3::Y;
|
||||
circle_coordinates_closed(radius, self.major_resolution)
|
||||
.map(|vec2| Vec3::new(vec2.x, 0.0, vec2.y) + translation)
|
||||
.map(|vec3| self.isometry * vec3)
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
// along the major circle draw orthogonal minor circles
|
||||
let affine = rotate_then_translate_3d(*rotation, *position);
|
||||
circle_coordinates(*major_radius, *major_resolution)
|
||||
.map(|p| Vec3::new(p.x, 0.0, p.y))
|
||||
.flat_map(|major_circle_point| {
|
||||
let minor_center = affine(major_circle_point);
|
||||
[&inner, &outer, &top, &bottom]
|
||||
.iter()
|
||||
.flat_map(|points| points.windows(2).map(|win| (win[0], win[1])))
|
||||
.for_each(|(start, end)| {
|
||||
self.gizmos.line(start, end, self.color);
|
||||
});
|
||||
|
||||
// direction facing from the center of the torus towards the minor circles center
|
||||
let dir_to_translation = (minor_center - *position).normalize();
|
||||
|
||||
// the minor circle is draw with 4 arcs this is done to make the minor circle
|
||||
// connect properly with each of the major circles
|
||||
let circle_points = [dir_to_translation, normal, -dir_to_translation, -normal]
|
||||
.map(|offset| minor_center + offset.normalize() * *minor_radius);
|
||||
circle_points
|
||||
.into_iter()
|
||||
.zip(circle_points.into_iter().cycle().skip(1))
|
||||
.map(move |(from, to)| (minor_center, from, to))
|
||||
.collect::<Vec<_>>()
|
||||
inner
|
||||
.into_iter()
|
||||
.zip(top)
|
||||
.zip(outer)
|
||||
.zip(bottom)
|
||||
.flat_map(|(((inner, top), outer), bottom)| {
|
||||
let center = (inner + top + outer + bottom) * 0.25;
|
||||
[(inner, top), (top, outer), (outer, bottom), (bottom, inner)]
|
||||
.map(|(start, end)| (start, end, center))
|
||||
})
|
||||
.for_each(|(center, from, to)| {
|
||||
gizmos
|
||||
.short_arc_3d_between(center, from, to, *color)
|
||||
.resolution(*minor_resolution);
|
||||
.for_each(|(from, to, center)| {
|
||||
self.gizmos
|
||||
.short_arc_3d_between(center, from, to, self.color)
|
||||
.resolution(self.minor_resolution);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1065,23 +908,20 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Tetrahedron> for Gizmos<'w, '
|
|||
fn primitive_3d(
|
||||
&mut self,
|
||||
primitive: &Tetrahedron,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: impl Into<Color>,
|
||||
) -> Self::Output<'_> {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let [a, b, c, d] = primitive
|
||||
.vertices
|
||||
.map(rotate_then_translate_3d(rotation, position));
|
||||
let [a, b, c, d] = primitive.vertices.map(|vec3| isometry * vec3);
|
||||
|
||||
let lines = [(a, b), (a, c), (a, d), (b, c), (b, d), (c, d)];
|
||||
|
||||
let color = color.into();
|
||||
for (a, b) in lines.into_iter() {
|
||||
self.line(a, b, color);
|
||||
}
|
||||
lines.into_iter().for_each(|(start, end)| {
|
||||
self.line(start, end, color);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,6 @@
|
|||
use std::f32::consts::TAU;
|
||||
|
||||
use bevy_color::Color;
|
||||
use bevy_math::{Mat2, Quat, Vec2, Vec3};
|
||||
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
|
||||
/// Performs an isometric transformation on 2D vectors.
|
||||
///
|
||||
/// This function takes angle and a position vector, and returns a closure that applies
|
||||
/// the isometric transformation to any given 2D vector. The transformation involves rotating
|
||||
/// the vector by the specified angle and then translating it by the given position.
|
||||
pub(crate) fn rotate_then_translate_2d(angle: f32, position: Vec2) -> impl Fn(Vec2) -> Vec2 {
|
||||
move |v| Mat2::from_angle(angle) * v + position
|
||||
}
|
||||
|
||||
/// Performs an isometric transformation on 3D vectors.
|
||||
///
|
||||
/// This function takes a quaternion representing rotation and a 3D vector representing
|
||||
/// translation, and returns a closure that applies the isometric transformation to any
|
||||
/// given 3D vector. The transformation involves rotating the vector by the specified
|
||||
/// quaternion and then translating it by the given translation vector.
|
||||
pub(crate) fn rotate_then_translate_3d(rotation: Quat, translation: Vec3) -> impl Fn(Vec3) -> Vec3 {
|
||||
move |v| rotation * v + translation
|
||||
}
|
||||
use bevy_math::Vec2;
|
||||
|
||||
/// Calculates the `nth` coordinate of a circle.
|
||||
///
|
||||
|
@ -37,6 +15,8 @@ pub(crate) fn single_circle_coordinate(radius: f32, resolution: u32, nth_point:
|
|||
|
||||
/// Generates an iterator over the coordinates of a circle.
|
||||
///
|
||||
/// The coordinates form a open circle, meaning the first and last points aren't the same.
|
||||
///
|
||||
/// This function creates an iterator that yields the positions of points approximating a
|
||||
/// circle with the given radius, divided into linear segments. The iterator produces `resolution`
|
||||
/// number of points.
|
||||
|
@ -46,27 +26,18 @@ pub(crate) fn circle_coordinates(radius: f32, resolution: u32) -> impl Iterator<
|
|||
.take(resolution as usize)
|
||||
}
|
||||
|
||||
/// Draws a circle in 3D space.
|
||||
/// Generates an iterator over the coordinates of a circle.
|
||||
///
|
||||
/// # Note
|
||||
/// The coordinates form a closed circle, meaning the first and last points are the same.
|
||||
///
|
||||
/// This function is necessary to use instead of `gizmos.circle` for certain primitives to ensure that points align correctly. For example, the major circles of a torus are drawn with this method, and using `gizmos.circle` would result in the minor circles not being positioned precisely on the major circles' segment points.
|
||||
pub(crate) fn draw_circle_3d<Config, Clear>(
|
||||
gizmos: &mut Gizmos<'_, '_, Config, Clear>,
|
||||
/// This function creates an iterator that yields the positions of points approximating a
|
||||
/// circle with the given radius, divided into linear segments. The iterator produces `resolution`
|
||||
/// number of points.
|
||||
pub(crate) fn circle_coordinates_closed(
|
||||
radius: f32,
|
||||
resolution: u32,
|
||||
rotation: Quat,
|
||||
translation: Vec3,
|
||||
color: Color,
|
||||
) where
|
||||
Config: GizmoConfigGroup,
|
||||
Clear: 'static + Send + Sync,
|
||||
{
|
||||
let positions = (0..=resolution)
|
||||
.map(|frac| frac as f32 / resolution as f32)
|
||||
.map(|percentage| percentage * TAU)
|
||||
.map(|angle| Vec2::from(angle.sin_cos()) * radius)
|
||||
.map(|p| Vec3::new(p.x, 0.0, p.y))
|
||||
.map(rotate_then_translate_3d(rotation, translation));
|
||||
gizmos.linestrip(positions, color);
|
||||
) -> impl Iterator<Item = Vec2> {
|
||||
circle_coordinates(radius, resolution).chain(std::iter::once(single_circle_coordinate(
|
||||
radius, resolution, resolution,
|
||||
)))
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::f32::consts::FRAC_PI_2;
|
|||
|
||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||
use bevy_color::Color;
|
||||
use bevy_math::{Quat, Vec2, Vec3};
|
||||
use bevy_math::{Isometry2d, Isometry3d, Quat, Vec2, Vec3};
|
||||
use bevy_transform::components::Transform;
|
||||
|
||||
/// A builder returned by [`Gizmos::rounded_rect`] and [`Gizmos::rounded_rect_2d`]
|
||||
|
@ -23,8 +23,7 @@ pub struct RoundedCuboidBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
|
|||
config: RoundedBoxConfig,
|
||||
}
|
||||
struct RoundedBoxConfig {
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
color: Color,
|
||||
corner_radius: f32,
|
||||
arc_resolution: u32,
|
||||
|
@ -82,15 +81,14 @@ impl<T: GizmoConfigGroup> Drop for RoundedRectBuilder<'_, '_, '_, T> {
|
|||
// Handle cases where the rectangle collapses into simpler shapes
|
||||
if outer_half_size.x * outer_half_size.y == 0. {
|
||||
self.gizmos.line(
|
||||
config.position + config.rotation * -outer_half_size.extend(0.),
|
||||
config.position + config.rotation * outer_half_size.extend(0.),
|
||||
config.isometry * -outer_half_size.extend(0.),
|
||||
config.isometry * outer_half_size.extend(0.),
|
||||
config.color,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if corner_radius == 0. {
|
||||
self.gizmos
|
||||
.rect(config.position, config.rotation, self.size, config.color);
|
||||
self.gizmos.rect(config.isometry, self.size, config.color);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,7 +110,7 @@ impl<T: GizmoConfigGroup> Drop for RoundedRectBuilder<'_, '_, '_, T> {
|
|||
Vec3::new(-inner_half_size.x, inner_half_size.y, 0.),
|
||||
Vec3::new(-inner_half_size.x, outer_half_size.y, 0.),
|
||||
]
|
||||
.map(|v| config.position + config.rotation * v);
|
||||
.map(|vec3| config.isometry * vec3);
|
||||
|
||||
for chunk in vertices.chunks_exact(3) {
|
||||
self.gizmos
|
||||
|
@ -159,8 +157,8 @@ impl<T: GizmoConfigGroup> Drop for RoundedCuboidBuilder<'_, '_, '_, T> {
|
|||
|
||||
// Handle cases where the rounded cuboid collapses into simpler shapes
|
||||
if edge_radius == 0.0 {
|
||||
let transform = Transform::from_translation(config.position)
|
||||
.with_rotation(config.rotation)
|
||||
let transform = Transform::from_translation(config.isometry.translation.into())
|
||||
.with_rotation(config.isometry.rotation)
|
||||
.with_scale(self.size);
|
||||
self.gizmos.cuboid(transform, config.color);
|
||||
return;
|
||||
|
@ -181,12 +179,10 @@ impl<T: GizmoConfigGroup> Drop for RoundedCuboidBuilder<'_, '_, '_, T> {
|
|||
];
|
||||
|
||||
for (position, size, rotation) in rects {
|
||||
let world_rotation = config.rotation * rotation;
|
||||
let local_position = config.rotation * (position * inner_half_size);
|
||||
let local_position = position * inner_half_size;
|
||||
self.gizmos
|
||||
.rounded_rect(
|
||||
config.position + local_position,
|
||||
world_rotation,
|
||||
config.isometry * Isometry3d::new(local_position, rotation),
|
||||
size,
|
||||
config.color,
|
||||
)
|
||||
|
@ -195,8 +191,7 @@ impl<T: GizmoConfigGroup> Drop for RoundedCuboidBuilder<'_, '_, '_, T> {
|
|||
|
||||
self.gizmos
|
||||
.rounded_rect(
|
||||
config.position - local_position,
|
||||
world_rotation,
|
||||
config.isometry * Isometry3d::new(-local_position, rotation),
|
||||
size,
|
||||
config.color,
|
||||
)
|
||||
|
@ -213,8 +208,11 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `position`: The center point of the rectangle.
|
||||
/// - `rotation`: defines orientation of the rectangle, by default we assume the rectangle is contained in a plane parallel to the XY plane.
|
||||
/// - `isometry` defines the translation and rotation of the rectangle.
|
||||
/// - the translation specifies the center of the rectangle
|
||||
/// - defines orientation of the rectangle, by default we
|
||||
/// assume the rectangle is contained in a plane parallel
|
||||
/// to the XY plane.
|
||||
/// - `size`: defines the size of the rectangle. This refers to the 'outer size', similar to a bounding box.
|
||||
/// - `color`: color of the rectangle
|
||||
///
|
||||
|
@ -231,8 +229,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
/// # use bevy_color::palettes::css::GREEN;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.rounded_rect(
|
||||
/// Vec3::ZERO,
|
||||
/// Quat::IDENTITY,
|
||||
/// Isometry3d::IDENTITY,
|
||||
/// Vec2::ONE,
|
||||
/// GREEN
|
||||
/// )
|
||||
|
@ -243,8 +240,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
/// ```
|
||||
pub fn rounded_rect(
|
||||
&mut self,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
size: Vec2,
|
||||
color: impl Into<Color>,
|
||||
) -> RoundedRectBuilder<'_, 'w, 's, T> {
|
||||
|
@ -252,8 +248,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
RoundedRectBuilder {
|
||||
gizmos: self,
|
||||
config: RoundedBoxConfig {
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
color: color.into(),
|
||||
corner_radius,
|
||||
arc_resolution: DEFAULT_ARC_RESOLUTION,
|
||||
|
@ -268,8 +263,10 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `position`: The center point of the rectangle.
|
||||
/// - `rotation`: defines orientation of the rectangle.
|
||||
/// - `isometry` defines the translation and rotation of the rectangle.
|
||||
/// - the translation specifies the center of the rectangle
|
||||
/// - defines orientation of the rectangle, by default we
|
||||
/// assume the rectangle aligned with all axes.
|
||||
/// - `size`: defines the size of the rectangle. This refers to the 'outer size', similar to a bounding box.
|
||||
/// - `color`: color of the rectangle
|
||||
///
|
||||
|
@ -286,8 +283,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
/// # use bevy_color::palettes::css::GREEN;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.rounded_rect_2d(
|
||||
/// Vec2::ZERO,
|
||||
/// 0.,
|
||||
/// Isometry2d::IDENTITY,
|
||||
/// Vec2::ONE,
|
||||
/// GREEN
|
||||
/// )
|
||||
|
@ -298,8 +294,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
/// ```
|
||||
pub fn rounded_rect_2d(
|
||||
&mut self,
|
||||
position: Vec2,
|
||||
rotation: f32,
|
||||
isometry: Isometry2d,
|
||||
size: Vec2,
|
||||
color: impl Into<Color>,
|
||||
) -> RoundedRectBuilder<'_, 'w, 's, T> {
|
||||
|
@ -307,8 +302,10 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
RoundedRectBuilder {
|
||||
gizmos: self,
|
||||
config: RoundedBoxConfig {
|
||||
position: position.extend(0.),
|
||||
rotation: Quat::from_rotation_z(rotation),
|
||||
isometry: Isometry3d::new(
|
||||
isometry.translation.extend(0.0),
|
||||
Quat::from_rotation_z(isometry.rotation.as_radians()),
|
||||
),
|
||||
color: color.into(),
|
||||
corner_radius,
|
||||
arc_resolution: DEFAULT_ARC_RESOLUTION,
|
||||
|
@ -323,8 +320,10 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `position`: The center point of the cuboid.
|
||||
/// - `rotation`: defines orientation of the cuboid.
|
||||
/// - `isometry` defines the translation and rotation of the cuboid.
|
||||
/// - the translation specifies the center of the cuboid
|
||||
/// - defines orientation of the cuboid, by default we
|
||||
/// assume the cuboid aligned with all axes.
|
||||
/// - `size`: defines the size of the cuboid. This refers to the 'outer size', similar to a bounding box.
|
||||
/// - `color`: color of the cuboid
|
||||
///
|
||||
|
@ -341,8 +340,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
/// # use bevy_color::palettes::css::GREEN;
|
||||
/// fn system(mut gizmos: Gizmos) {
|
||||
/// gizmos.rounded_cuboid(
|
||||
/// Vec3::ZERO,
|
||||
/// Quat::IDENTITY,
|
||||
/// Isometry3d::IDENTITY,
|
||||
/// Vec3::ONE,
|
||||
/// GREEN
|
||||
/// )
|
||||
|
@ -353,8 +351,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
/// ```
|
||||
pub fn rounded_cuboid(
|
||||
&mut self,
|
||||
position: Vec3,
|
||||
rotation: Quat,
|
||||
isometry: Isometry3d,
|
||||
size: Vec3,
|
||||
color: impl Into<Color>,
|
||||
) -> RoundedCuboidBuilder<'_, 'w, 's, T> {
|
||||
|
@ -362,8 +359,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
|||
RoundedCuboidBuilder {
|
||||
gizmos: self,
|
||||
config: RoundedBoxConfig {
|
||||
position,
|
||||
rotation,
|
||||
isometry,
|
||||
color: color.into(),
|
||||
corner_radius,
|
||||
arc_resolution: DEFAULT_ARC_RESOLUTION,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! This example demonstrates how to use the `Camera::viewport_to_world_2d` method.
|
||||
|
||||
use bevy::{color::palettes::basic::WHITE, prelude::*};
|
||||
use bevy::{color::palettes::basic::WHITE, math::Isometry2d, prelude::*};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
|
@ -30,7 +30,7 @@ fn draw_cursor(
|
|||
return;
|
||||
};
|
||||
|
||||
gizmos.circle_2d(point, 10., WHITE);
|
||||
gizmos.circle_2d(Isometry2d::from_translation(point), 10., WHITE);
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands) {
|
||||
|
|
|
@ -105,24 +105,25 @@ fn render_shapes(mut gizmos: Gizmos, query: Query<(&Shape, &Transform)>) {
|
|||
for (shape, transform) in query.iter() {
|
||||
let translation = transform.translation.xy();
|
||||
let rotation = transform.rotation.to_euler(EulerRot::YXZ).2;
|
||||
let isometry = Isometry2d::new(translation, Rot2::radians(rotation));
|
||||
match shape {
|
||||
Shape::Rectangle(r) => {
|
||||
gizmos.primitive_2d(r, translation, rotation, color);
|
||||
gizmos.primitive_2d(r, isometry, color);
|
||||
}
|
||||
Shape::Circle(c) => {
|
||||
gizmos.primitive_2d(c, translation, rotation, color);
|
||||
gizmos.primitive_2d(c, isometry, color);
|
||||
}
|
||||
Shape::Triangle(t) => {
|
||||
gizmos.primitive_2d(t, translation, rotation, color);
|
||||
gizmos.primitive_2d(t, isometry, color);
|
||||
}
|
||||
Shape::Line(l) => {
|
||||
gizmos.primitive_2d(l, translation, rotation, color);
|
||||
gizmos.primitive_2d(l, isometry, color);
|
||||
}
|
||||
Shape::Capsule(c) => {
|
||||
gizmos.primitive_2d(c, translation, rotation, color);
|
||||
gizmos.primitive_2d(c, isometry, color);
|
||||
}
|
||||
Shape::Polygon(p) => {
|
||||
gizmos.primitive_2d(p, translation, rotation, color);
|
||||
gizmos.primitive_2d(p, isometry, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,10 +186,14 @@ fn render_volumes(mut gizmos: Gizmos, query: Query<(&CurrentVolume, &Intersects)
|
|||
let color = if **intersects { AQUA } else { ORANGE_RED };
|
||||
match volume {
|
||||
CurrentVolume::Aabb(a) => {
|
||||
gizmos.rect_2d(a.center(), 0., a.half_size() * 2., color);
|
||||
gizmos.rect_2d(
|
||||
Isometry2d::from_translation(a.center()),
|
||||
a.half_size() * 2.,
|
||||
color,
|
||||
);
|
||||
}
|
||||
CurrentVolume::Circle(c) => {
|
||||
gizmos.circle_2d(c.center(), c.radius(), color);
|
||||
gizmos.circle_2d(Isometry2d::from_translation(c.center()), c.radius(), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +288,7 @@ fn setup(mut commands: Commands) {
|
|||
|
||||
fn draw_filled_circle(gizmos: &mut Gizmos, position: Vec2, color: Srgba) {
|
||||
for r in [1., 2., 3.] {
|
||||
gizmos.circle_2d(position, r, color);
|
||||
gizmos.circle_2d(Isometry2d::from_translation(position), r, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,8 +358,9 @@ fn aabb_cast_system(
|
|||
**intersects = toi.is_some();
|
||||
if let Some(toi) = toi {
|
||||
gizmos.rect_2d(
|
||||
aabb_cast.ray.ray.origin + *aabb_cast.ray.ray.direction * toi,
|
||||
0.,
|
||||
Isometry2d::from_translation(
|
||||
aabb_cast.ray.ray.origin + *aabb_cast.ray.ray.direction * toi,
|
||||
),
|
||||
aabb_cast.aabb.half_size() * 2.,
|
||||
LIME,
|
||||
);
|
||||
|
@ -382,7 +388,9 @@ fn bounding_circle_cast_system(
|
|||
**intersects = toi.is_some();
|
||||
if let Some(toi) = toi {
|
||||
gizmos.circle_2d(
|
||||
circle_cast.ray.ray.origin + *circle_cast.ray.ray.direction * toi,
|
||||
Isometry2d::from_translation(
|
||||
circle_cast.ray.ray.origin + *circle_cast.ray.ray.direction * toi,
|
||||
),
|
||||
circle_cast.circle.radius(),
|
||||
LIME,
|
||||
);
|
||||
|
@ -403,7 +411,11 @@ fn aabb_intersection_system(
|
|||
) {
|
||||
let center = get_intersection_position(&time);
|
||||
let aabb = Aabb2d::new(center, Vec2::splat(50.));
|
||||
gizmos.rect_2d(center, 0., aabb.half_size() * 2., YELLOW);
|
||||
gizmos.rect_2d(
|
||||
Isometry2d::from_translation(center),
|
||||
aabb.half_size() * 2.,
|
||||
YELLOW,
|
||||
);
|
||||
|
||||
for (volume, mut intersects) in volumes.iter_mut() {
|
||||
let hit = match volume {
|
||||
|
@ -422,7 +434,11 @@ fn circle_intersection_system(
|
|||
) {
|
||||
let center = get_intersection_position(&time);
|
||||
let circle = BoundingCircle::new(center, 50.);
|
||||
gizmos.circle_2d(center, circle.radius(), YELLOW);
|
||||
gizmos.circle_2d(
|
||||
Isometry2d::from_translation(center),
|
||||
circle.radius(),
|
||||
YELLOW,
|
||||
);
|
||||
|
||||
for (volume, mut intersects) in volumes.iter_mut() {
|
||||
let hit = match volume {
|
||||
|
|
|
@ -120,9 +120,17 @@ fn draw_bounds<Shape: Bounded2d + Send + Sync + 'static>(
|
|||
let isometry = Isometry2d::new(translation, Rot2::radians(rotation));
|
||||
|
||||
let aabb = shape.0.aabb_2d(isometry);
|
||||
gizmos.rect_2d(aabb.center(), 0.0, aabb.half_size() * 2.0, RED);
|
||||
gizmos.rect_2d(
|
||||
Isometry2d::from_translation(aabb.center()),
|
||||
aabb.half_size() * 2.0,
|
||||
RED,
|
||||
);
|
||||
|
||||
let bounding_circle = shape.0.bounding_circle(isometry);
|
||||
gizmos.circle_2d(bounding_circle.center, bounding_circle.radius(), BLUE);
|
||||
gizmos.circle_2d(
|
||||
Isometry2d::from_translation(bounding_circle.center),
|
||||
bounding_circle.radius(),
|
||||
BLUE,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,14 @@ fn draw_cursor(
|
|||
let point = ray.get_point(distance);
|
||||
|
||||
// Draw a circle just above the ground plane at that position.
|
||||
gizmos.circle(point + ground.up() * 0.01, ground.up(), 0.2, Color::WHITE);
|
||||
gizmos.circle(
|
||||
Isometry3d::new(
|
||||
point + ground.up() * 0.01,
|
||||
Quat::from_rotation_arc(Vec3::Z, ground.up().as_vec3()),
|
||||
),
|
||||
0.2,
|
||||
Color::WHITE,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Demonstrates how to observe life-cycle triggers as well as define custom ones.
|
||||
|
||||
use bevy::{
|
||||
math::Isometry2d,
|
||||
prelude::*,
|
||||
utils::{HashMap, HashSet},
|
||||
};
|
||||
|
@ -165,7 +166,7 @@ fn explode_mine(trigger: Trigger<Explode>, query: Query<&Mine>, mut commands: Co
|
|||
fn draw_shapes(mut gizmos: Gizmos, mines: Query<&Mine>) {
|
||||
for mine in &mines {
|
||||
gizmos.circle_2d(
|
||||
mine.pos,
|
||||
Isometry2d::from_translation(mine.pos),
|
||||
mine.size,
|
||||
Color::hsl((mine.size - 4.0) / 16.0 * 360.0, 1.0, 0.8),
|
||||
);
|
||||
|
|
|
@ -49,8 +49,7 @@ fn draw_example_collection(
|
|||
|
||||
gizmos
|
||||
.grid_2d(
|
||||
Vec2::ZERO,
|
||||
0.0,
|
||||
Isometry2d::IDENTITY,
|
||||
UVec2::new(16, 9),
|
||||
Vec2::new(80., 80.),
|
||||
// Dark gray
|
||||
|
@ -66,21 +65,26 @@ fn draw_example_collection(
|
|||
(Vec2::Y * 300., BLUE),
|
||||
]);
|
||||
|
||||
gizmos.rect_2d(Vec2::ZERO, 0., Vec2::splat(650.), BLACK);
|
||||
gizmos.rect_2d(Isometry2d::IDENTITY, Vec2::splat(650.), BLACK);
|
||||
|
||||
gizmos.cross_2d(Vec2::new(-160., 120.), 0., 12., FUCHSIA);
|
||||
gizmos.cross_2d(
|
||||
Isometry2d::from_translation(Vec2::new(-160., 120.)),
|
||||
12.,
|
||||
FUCHSIA,
|
||||
);
|
||||
|
||||
my_gizmos
|
||||
.rounded_rect_2d(Vec2::ZERO, 0., Vec2::splat(630.), BLACK)
|
||||
.rounded_rect_2d(Isometry2d::IDENTITY, Vec2::splat(630.), BLACK)
|
||||
.corner_radius((time.elapsed_seconds() / 3.).cos() * 100.);
|
||||
|
||||
// Circles have 32 line-segments by default.
|
||||
// You may want to increase this for larger circles.
|
||||
my_gizmos.circle_2d(Vec2::ZERO, 300., NAVY).resolution(64);
|
||||
my_gizmos
|
||||
.circle_2d(Isometry2d::from_translation(Vec2::ZERO), 300., NAVY)
|
||||
.resolution(64);
|
||||
|
||||
my_gizmos.ellipse_2d(
|
||||
Vec2::ZERO,
|
||||
time.elapsed_seconds() % TAU,
|
||||
Isometry2d::new(Vec2::ZERO, Rot2::radians(time.elapsed_seconds() % TAU)),
|
||||
Vec2::new(100., 200.),
|
||||
YELLOW_GREEN,
|
||||
);
|
||||
|
|
|
@ -83,41 +83,48 @@ fn draw_example_collection(
|
|||
time: Res<Time>,
|
||||
) {
|
||||
gizmos.grid(
|
||||
Vec3::ZERO,
|
||||
Quat::from_rotation_x(PI / 2.),
|
||||
Isometry3d::from_rotation(Quat::from_rotation_x(PI / 2.)),
|
||||
UVec2::splat(20),
|
||||
Vec2::new(2., 2.),
|
||||
// Light gray
|
||||
LinearRgba::gray(0.65),
|
||||
);
|
||||
gizmos.grid(
|
||||
Vec3::ONE * 10.0,
|
||||
Quat::from_rotation_x(PI / 3. * 2.),
|
||||
Isometry3d::new(Vec3::ONE * 10.0, Quat::from_rotation_x(PI / 3. * 2.)),
|
||||
UVec2::splat(20),
|
||||
Vec2::new(2., 2.),
|
||||
PURPLE,
|
||||
);
|
||||
gizmos.sphere(Vec3::ONE * 10.0, Quat::default(), 1.0, PURPLE);
|
||||
gizmos.sphere(Isometry3d::from_translation(Vec3::ONE * 10.0), 1.0, PURPLE);
|
||||
|
||||
gizmos.cuboid(
|
||||
Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.25)),
|
||||
BLACK,
|
||||
);
|
||||
gizmos.rect(
|
||||
Vec3::new(time.elapsed_seconds().cos() * 2.5, 1., 0.),
|
||||
Quat::from_rotation_y(PI / 2.),
|
||||
Isometry3d::new(
|
||||
Vec3::new(time.elapsed_seconds().cos() * 2.5, 1., 0.),
|
||||
Quat::from_rotation_y(PI / 2.),
|
||||
),
|
||||
Vec2::splat(2.),
|
||||
LIME,
|
||||
);
|
||||
|
||||
gizmos.cross(Vec3::new(-1., 1., 1.), Quat::IDENTITY, 0.5, FUCHSIA);
|
||||
gizmos.cross(
|
||||
Isometry3d::from_translation(Vec3::new(-1., 1., 1.)),
|
||||
0.5,
|
||||
FUCHSIA,
|
||||
);
|
||||
|
||||
my_gizmos.sphere(Vec3::new(1., 0.5, 0.), Quat::IDENTITY, 0.5, RED);
|
||||
my_gizmos.sphere(
|
||||
Isometry3d::from_translation(Vec3::new(1., 0.5, 0.)),
|
||||
0.5,
|
||||
RED,
|
||||
);
|
||||
|
||||
my_gizmos
|
||||
.rounded_cuboid(
|
||||
Vec3::new(-2.0, 0.75, -0.75),
|
||||
Quat::IDENTITY,
|
||||
Isometry3d::from_translation(Vec3::new(-2.0, 0.75, -0.75)),
|
||||
Vec3::splat(0.9),
|
||||
TURQUOISE,
|
||||
)
|
||||
|
@ -136,20 +143,30 @@ fn draw_example_collection(
|
|||
.arc_3d(
|
||||
180.0_f32.to_radians(),
|
||||
0.2,
|
||||
Vec3::ONE,
|
||||
Quat::from_rotation_arc(Vec3::Y, Vec3::ONE.normalize()),
|
||||
Isometry3d::new(
|
||||
Vec3::ONE,
|
||||
Quat::from_rotation_arc(Vec3::Y, Vec3::ONE.normalize()),
|
||||
),
|
||||
ORANGE,
|
||||
)
|
||||
.resolution(10);
|
||||
|
||||
// Circles have 32 line-segments by default.
|
||||
my_gizmos.circle(Vec3::ZERO, Dir3::Y, 3., BLACK);
|
||||
my_gizmos.circle(
|
||||
Isometry3d::from_rotation(Quat::from_rotation_arc(Vec3::Z, Vec3::Y)),
|
||||
3.,
|
||||
BLACK,
|
||||
);
|
||||
// You may want to increase this for larger circles or spheres.
|
||||
my_gizmos
|
||||
.circle(Vec3::ZERO, Dir3::Y, 3.1, NAVY)
|
||||
.circle(
|
||||
Isometry3d::from_rotation(Quat::from_rotation_arc(Vec3::Z, Vec3::Y)),
|
||||
3.1,
|
||||
NAVY,
|
||||
)
|
||||
.resolution(64);
|
||||
my_gizmos
|
||||
.sphere(Vec3::ZERO, Quat::IDENTITY, 3.2, BLACK)
|
||||
.sphere(Isometry3d::IDENTITY, 3.2, BLACK)
|
||||
.resolution(64);
|
||||
|
||||
gizmos.arrow(Vec3::ZERO, Vec3::ONE * 1.5, YELLOW);
|
||||
|
|
|
@ -6,7 +6,7 @@ use bevy::{
|
|||
ecs::system::Commands,
|
||||
gizmos::gizmos::Gizmos,
|
||||
input::{mouse::MouseButtonInput, ButtonState},
|
||||
math::{cubic_splines::*, vec2},
|
||||
math::{cubic_splines::*, vec2, Isometry2d},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
|
@ -197,7 +197,11 @@ fn draw_control_points(
|
|||
mut gizmos: Gizmos,
|
||||
) {
|
||||
for &(point, tangent) in &control_points.points_and_tangents {
|
||||
gizmos.circle_2d(point, 10.0, Color::srgb(0.0, 1.0, 0.0));
|
||||
gizmos.circle_2d(
|
||||
Isometry2d::from_translation(point),
|
||||
10.0,
|
||||
Color::srgb(0.0, 1.0, 0.0),
|
||||
);
|
||||
|
||||
if matches!(*spline_mode, SplineMode::Hermite) {
|
||||
gizmos.arrow_2d(point, point + tangent, Color::srgb(1.0, 0.0, 0.0));
|
||||
|
@ -399,8 +403,16 @@ fn draw_edit_move(
|
|||
return;
|
||||
};
|
||||
|
||||
gizmos.circle_2d(start, 10.0, Color::srgb(0.0, 1.0, 0.7));
|
||||
gizmos.circle_2d(start, 7.0, Color::srgb(0.0, 1.0, 0.7));
|
||||
gizmos.circle_2d(
|
||||
Isometry2d::from_translation(start),
|
||||
10.0,
|
||||
Color::srgb(0.0, 1.0, 0.7),
|
||||
);
|
||||
gizmos.circle_2d(
|
||||
Isometry2d::from_translation(start),
|
||||
7.0,
|
||||
Color::srgb(0.0, 1.0, 0.7),
|
||||
);
|
||||
gizmos.arrow_2d(start, end, Color::srgb(1.0, 0.0, 0.7));
|
||||
}
|
||||
|
||||
|
|
|
@ -211,14 +211,22 @@ fn bounding_shapes_2d(
|
|||
// Get the AABB of the primitive with the rotation and translation of the mesh.
|
||||
let aabb = HEART.aabb_2d(isometry);
|
||||
|
||||
gizmos.rect_2d(aabb.center(), 0., aabb.half_size() * 2., WHITE);
|
||||
gizmos.rect_2d(
|
||||
Isometry2d::from_translation(aabb.center()),
|
||||
aabb.half_size() * 2.,
|
||||
WHITE,
|
||||
);
|
||||
}
|
||||
BoundingShape::BoundingSphere => {
|
||||
// Get the bounding sphere of the primitive with the rotation and translation of the mesh.
|
||||
let bounding_circle = HEART.bounding_circle(isometry);
|
||||
|
||||
gizmos
|
||||
.circle_2d(bounding_circle.center(), bounding_circle.radius(), WHITE)
|
||||
.circle_2d(
|
||||
Isometry2d::from_translation(bounding_circle.center()),
|
||||
bounding_circle.radius(),
|
||||
WHITE,
|
||||
)
|
||||
.resolution(64);
|
||||
}
|
||||
}
|
||||
|
@ -249,8 +257,7 @@ fn bounding_shapes_3d(
|
|||
|
||||
gizmos.primitive_3d(
|
||||
&Cuboid::from_size(Vec3::from(aabb.half_size()) * 2.),
|
||||
aabb.center().into(),
|
||||
Quat::IDENTITY,
|
||||
Isometry3d::from_translation(aabb.center()),
|
||||
WHITE,
|
||||
);
|
||||
}
|
||||
|
@ -259,8 +266,7 @@ fn bounding_shapes_3d(
|
|||
let bounding_sphere = EXTRUSION.bounding_sphere(transform.to_isometry());
|
||||
|
||||
gizmos.sphere(
|
||||
bounding_sphere.center().into(),
|
||||
Quat::IDENTITY,
|
||||
Isometry3d::from_translation(bounding_sphere.center()),
|
||||
bounding_sphere.radius(),
|
||||
WHITE,
|
||||
);
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
#![allow(clippy::match_same_arms)]
|
||||
|
||||
use bevy::{
|
||||
input::common_conditions::input_just_pressed, prelude::*, sprite::MaterialMesh2dBundle,
|
||||
input::common_conditions::input_just_pressed, math::Isometry2d, prelude::*,
|
||||
sprite::MaterialMesh2dBundle,
|
||||
};
|
||||
|
||||
const LEFT_RIGHT_OFFSET_2D: f32 = 200.0;
|
||||
|
@ -445,39 +446,40 @@ fn in_mode(active: CameraActive) -> impl Fn(Res<State<CameraActive>>) -> bool {
|
|||
fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time: Res<Time>) {
|
||||
const POSITION: Vec2 = Vec2::new(-LEFT_RIGHT_OFFSET_2D, 0.0);
|
||||
let angle = time.elapsed_seconds();
|
||||
let isometry = Isometry2d::new(POSITION, Rot2::radians(angle));
|
||||
let color = Color::WHITE;
|
||||
|
||||
match state.get() {
|
||||
PrimitiveSelected::RectangleAndCuboid => {
|
||||
gizmos.primitive_2d(&RECTANGLE, POSITION, angle, color);
|
||||
gizmos.primitive_2d(&RECTANGLE, isometry, color);
|
||||
}
|
||||
PrimitiveSelected::CircleAndSphere => {
|
||||
gizmos.primitive_2d(&CIRCLE, POSITION, angle, color);
|
||||
gizmos.primitive_2d(&CIRCLE, isometry, color);
|
||||
}
|
||||
PrimitiveSelected::Ellipse => drop(gizmos.primitive_2d(&ELLIPSE, POSITION, angle, color)),
|
||||
PrimitiveSelected::Triangle => gizmos.primitive_2d(&TRIANGLE_2D, POSITION, angle, color),
|
||||
PrimitiveSelected::Plane => gizmos.primitive_2d(&PLANE_2D, POSITION, angle, color),
|
||||
PrimitiveSelected::Line => drop(gizmos.primitive_2d(&LINE2D, POSITION, angle, color)),
|
||||
PrimitiveSelected::Ellipse => drop(gizmos.primitive_2d(&ELLIPSE, isometry, color)),
|
||||
PrimitiveSelected::Triangle => gizmos.primitive_2d(&TRIANGLE_2D, isometry, color),
|
||||
PrimitiveSelected::Plane => gizmos.primitive_2d(&PLANE_2D, isometry, color),
|
||||
PrimitiveSelected::Line => drop(gizmos.primitive_2d(&LINE2D, isometry, color)),
|
||||
PrimitiveSelected::Segment => {
|
||||
drop(gizmos.primitive_2d(&SEGMENT_2D, POSITION, angle, color));
|
||||
drop(gizmos.primitive_2d(&SEGMENT_2D, isometry, color));
|
||||
}
|
||||
PrimitiveSelected::Polyline => gizmos.primitive_2d(&POLYLINE_2D, POSITION, angle, color),
|
||||
PrimitiveSelected::Polygon => gizmos.primitive_2d(&POLYGON_2D, POSITION, angle, color),
|
||||
PrimitiveSelected::Polyline => gizmos.primitive_2d(&POLYLINE_2D, isometry, color),
|
||||
PrimitiveSelected::Polygon => gizmos.primitive_2d(&POLYGON_2D, isometry, color),
|
||||
PrimitiveSelected::RegularPolygon => {
|
||||
gizmos.primitive_2d(®ULAR_POLYGON, POSITION, angle, color);
|
||||
gizmos.primitive_2d(®ULAR_POLYGON, isometry, color);
|
||||
}
|
||||
PrimitiveSelected::Capsule => gizmos.primitive_2d(&CAPSULE_2D, POSITION, angle, color),
|
||||
PrimitiveSelected::Capsule => gizmos.primitive_2d(&CAPSULE_2D, isometry, color),
|
||||
PrimitiveSelected::Cylinder => {}
|
||||
PrimitiveSelected::Cone => {}
|
||||
PrimitiveSelected::ConicalFrustum => {}
|
||||
PrimitiveSelected::Torus => drop(gizmos.primitive_2d(&ANNULUS, POSITION, angle, color)),
|
||||
PrimitiveSelected::Torus => drop(gizmos.primitive_2d(&ANNULUS, isometry, color)),
|
||||
PrimitiveSelected::Tetrahedron => {}
|
||||
PrimitiveSelected::Arc => gizmos.primitive_2d(&ARC, POSITION, angle, color),
|
||||
PrimitiveSelected::Arc => gizmos.primitive_2d(&ARC, isometry, color),
|
||||
PrimitiveSelected::CircularSector => {
|
||||
gizmos.primitive_2d(&CIRCULAR_SECTOR, POSITION, angle, color);
|
||||
gizmos.primitive_2d(&CIRCULAR_SECTOR, isometry, color);
|
||||
}
|
||||
PrimitiveSelected::CircularSegment => {
|
||||
gizmos.primitive_2d(&CIRCULAR_SEGMENT, POSITION, angle, color);
|
||||
gizmos.primitive_2d(&CIRCULAR_SEGMENT, isometry, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -660,53 +662,54 @@ fn draw_gizmos_3d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time
|
|||
.try_normalize()
|
||||
.unwrap_or(Vec3::Z),
|
||||
);
|
||||
let isometry = Isometry3d::new(POSITION, rotation);
|
||||
let color = Color::WHITE;
|
||||
let resolution = 10;
|
||||
|
||||
match state.get() {
|
||||
PrimitiveSelected::RectangleAndCuboid => {
|
||||
gizmos.primitive_3d(&CUBOID, POSITION, rotation, color);
|
||||
gizmos.primitive_3d(&CUBOID, isometry, color);
|
||||
}
|
||||
PrimitiveSelected::CircleAndSphere => drop(
|
||||
gizmos
|
||||
.primitive_3d(&SPHERE, POSITION, rotation, color)
|
||||
.primitive_3d(&SPHERE, isometry, color)
|
||||
.resolution(resolution),
|
||||
),
|
||||
PrimitiveSelected::Ellipse => {}
|
||||
PrimitiveSelected::Triangle => gizmos.primitive_3d(&TRIANGLE_3D, POSITION, rotation, color),
|
||||
PrimitiveSelected::Plane => drop(gizmos.primitive_3d(&PLANE_3D, POSITION, rotation, color)),
|
||||
PrimitiveSelected::Line => gizmos.primitive_3d(&LINE3D, POSITION, rotation, color),
|
||||
PrimitiveSelected::Segment => gizmos.primitive_3d(&SEGMENT_3D, POSITION, rotation, color),
|
||||
PrimitiveSelected::Polyline => gizmos.primitive_3d(&POLYLINE_3D, POSITION, rotation, color),
|
||||
PrimitiveSelected::Triangle => gizmos.primitive_3d(&TRIANGLE_3D, isometry, color),
|
||||
PrimitiveSelected::Plane => drop(gizmos.primitive_3d(&PLANE_3D, isometry, color)),
|
||||
PrimitiveSelected::Line => gizmos.primitive_3d(&LINE3D, isometry, color),
|
||||
PrimitiveSelected::Segment => gizmos.primitive_3d(&SEGMENT_3D, isometry, color),
|
||||
PrimitiveSelected::Polyline => gizmos.primitive_3d(&POLYLINE_3D, isometry, color),
|
||||
PrimitiveSelected::Polygon => {}
|
||||
PrimitiveSelected::RegularPolygon => {}
|
||||
PrimitiveSelected::Capsule => drop(
|
||||
gizmos
|
||||
.primitive_3d(&CAPSULE_3D, POSITION, rotation, color)
|
||||
.primitive_3d(&CAPSULE_3D, isometry, color)
|
||||
.resolution(resolution),
|
||||
),
|
||||
PrimitiveSelected::Cylinder => drop(
|
||||
gizmos
|
||||
.primitive_3d(&CYLINDER, POSITION, rotation, color)
|
||||
.primitive_3d(&CYLINDER, isometry, color)
|
||||
.resolution(resolution),
|
||||
),
|
||||
PrimitiveSelected::Cone => drop(
|
||||
gizmos
|
||||
.primitive_3d(&CONE, POSITION, rotation, color)
|
||||
.primitive_3d(&CONE, isometry, color)
|
||||
.resolution(resolution),
|
||||
),
|
||||
PrimitiveSelected::ConicalFrustum => {
|
||||
gizmos.primitive_3d(&CONICAL_FRUSTUM, POSITION, rotation, color);
|
||||
gizmos.primitive_3d(&CONICAL_FRUSTUM, isometry, color);
|
||||
}
|
||||
|
||||
PrimitiveSelected::Torus => drop(
|
||||
gizmos
|
||||
.primitive_3d(&TORUS, POSITION, rotation, color)
|
||||
.primitive_3d(&TORUS, isometry, color)
|
||||
.minor_resolution(resolution)
|
||||
.major_resolution(resolution),
|
||||
),
|
||||
PrimitiveSelected::Tetrahedron => {
|
||||
gizmos.primitive_3d(&TETRAHEDRON, POSITION, rotation, color);
|
||||
gizmos.primitive_3d(&TETRAHEDRON, isometry, color);
|
||||
}
|
||||
|
||||
PrimitiveSelected::Arc => {}
|
||||
|
|
Loading…
Reference in a new issue