More gizmos builders (#13261)
# Objective - Add GizmoBuilders for some primitives as discussed in #13233 ## Solution - `gizmos.primitive_2d(CIRCLE)` and `gizmos.primitive_2d(ELLIPSE)` now return `Ellipse2dBuilder` aswell. - `gizmos.primitive_3d(SPHERE)` and `gizmos.sphere()` now return the same `SphereBuilder`. - the `.circle_segments` method on the `SphereBuilder` that used to be returned by `.sphere()` is now called `.segments` - the sphere primitive gizmo now matches the `gizmos.sphere` gizmo - `gizmos.primitive_2d(ANNULUS)` now returns a `Annulus2dBuilder` allowing the configuration of the `segments` - gizmos cylinders and capsules now have only 1 line per axis, similar to `gizmos.sphere` ## Migration Guide - Some `gizmos.primitive_nd` methods now return some or different builders. You may need to adjust types and match statements - Replace any calls to `circle_segments()` with `.segments()` --------- Co-authored-by: Raphael Büttgenbach <62256001+solis-lumine-vorago@users.noreply.github.com>
This commit is contained in:
parent
cca4fc76de
commit
e6a0f75a63
@ -178,6 +178,45 @@ where
|
|||||||
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw a wireframe sphere in 3D made out of 3 circles around the axes.
|
||||||
|
///
|
||||||
|
/// This should be called for each frame the sphere needs to be rendered.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_gizmos::prelude::*;
|
||||||
|
/// # use bevy_render::prelude::*;
|
||||||
|
/// # use bevy_math::prelude::*;
|
||||||
|
/// # use bevy_color::Color;
|
||||||
|
/// fn system(mut gizmos: Gizmos) {
|
||||||
|
/// gizmos.sphere(Vec3::ZERO, Quat::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)
|
||||||
|
/// .resolution(64);
|
||||||
|
/// }
|
||||||
|
/// # bevy_ecs::system::assert_is_system(system);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn sphere(
|
||||||
|
&mut self,
|
||||||
|
position: Vec3,
|
||||||
|
rotation: Quat,
|
||||||
|
radius: f32,
|
||||||
|
color: impl Into<Color>,
|
||||||
|
) -> SphereBuilder<'_, 'w, 's, Config, Clear> {
|
||||||
|
SphereBuilder {
|
||||||
|
gizmos: self,
|
||||||
|
radius,
|
||||||
|
position,
|
||||||
|
rotation,
|
||||||
|
color: color.into(),
|
||||||
|
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder returned by [`Gizmos::ellipse`].
|
/// A builder returned by [`Gizmos::ellipse`].
|
||||||
@ -266,3 +305,66 @@ where
|
|||||||
self.gizmos.linestrip_2d(positions, self.color);
|
self.gizmos.linestrip_2d(positions, self.color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builder for configuring the drawing options of [`Sphere`].
|
||||||
|
pub struct SphereBuilder<'a, 'w, 's, Config, Clear>
|
||||||
|
where
|
||||||
|
Config: GizmoConfigGroup,
|
||||||
|
Clear: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
// Color of the sphere
|
||||||
|
color: Color,
|
||||||
|
|
||||||
|
// Number of line-segments used to approximate the sphere geometry
|
||||||
|
resolution: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Config, Clear> SphereBuilder<'_, '_, '_, Config, Clear>
|
||||||
|
where
|
||||||
|
Config: GizmoConfigGroup,
|
||||||
|
Clear: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
/// Set the number of line-segments used to approximate the sphere geometry.
|
||||||
|
pub fn resolution(mut self, resolution: usize) -> Self {
|
||||||
|
self.resolution = resolution;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Config, Clear> Drop for SphereBuilder<'_, '_, '_, Config, Clear>
|
||||||
|
where
|
||||||
|
Config: GizmoConfigGroup,
|
||||||
|
Clear: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.gizmos.enabled {
|
||||||
|
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;
|
||||||
|
self.gizmos
|
||||||
|
.circle(*center, Dir3::new_unchecked(normal), *radius, *color)
|
||||||
|
.resolution(*resolution);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,14 +2,13 @@
|
|||||||
|
|
||||||
use std::{iter, marker::PhantomData, mem};
|
use std::{iter, marker::PhantomData, mem};
|
||||||
|
|
||||||
use crate::circles::DEFAULT_CIRCLE_RESOLUTION;
|
|
||||||
use bevy_color::{Color, LinearRgba};
|
use bevy_color::{Color, LinearRgba};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Tick,
|
component::Tick,
|
||||||
system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam},
|
system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam},
|
||||||
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||||
};
|
};
|
||||||
use bevy_math::{Dir3, Quat, Rotation2d, Vec2, Vec3};
|
use bevy_math::{Quat, Rotation2d, Vec2, Vec3};
|
||||||
use bevy_transform::TransformPoint;
|
use bevy_transform::TransformPoint;
|
||||||
use bevy_utils::default;
|
use bevy_utils::default;
|
||||||
|
|
||||||
@ -459,45 +458,6 @@ where
|
|||||||
strip_colors.push(LinearRgba::NAN);
|
strip_colors.push(LinearRgba::NAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw a wireframe sphere in 3D made out of 3 circles around the axes.
|
|
||||||
///
|
|
||||||
/// This should be called for each frame the sphere needs to be rendered.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_gizmos::prelude::*;
|
|
||||||
/// # use bevy_render::prelude::*;
|
|
||||||
/// # use bevy_math::prelude::*;
|
|
||||||
/// # use bevy_color::Color;
|
|
||||||
/// fn system(mut gizmos: Gizmos) {
|
|
||||||
/// gizmos.sphere(Vec3::ZERO, Quat::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)
|
|
||||||
/// .resolution(64);
|
|
||||||
/// }
|
|
||||||
/// # bevy_ecs::system::assert_is_system(system);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn sphere(
|
|
||||||
&mut self,
|
|
||||||
position: Vec3,
|
|
||||||
rotation: Quat,
|
|
||||||
radius: f32,
|
|
||||||
color: impl Into<Color>,
|
|
||||||
) -> SphereBuilder<'_, 'w, 's, Config, Clear> {
|
|
||||||
SphereBuilder {
|
|
||||||
gizmos: self,
|
|
||||||
position,
|
|
||||||
rotation: rotation.normalize(),
|
|
||||||
radius,
|
|
||||||
color: color.into(),
|
|
||||||
resolution: DEFAULT_CIRCLE_RESOLUTION,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Draw a wireframe rectangle in 3D.
|
/// Draw a wireframe rectangle in 3D.
|
||||||
///
|
///
|
||||||
/// This should be called for each frame the rectangle needs to be rendered.
|
/// This should be called for each frame the rectangle needs to be rendered.
|
||||||
@ -790,49 +750,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder returned by [`Gizmos::sphere`].
|
|
||||||
pub struct SphereBuilder<'a, 'w, 's, Config, Clear = ()>
|
|
||||||
where
|
|
||||||
Config: GizmoConfigGroup,
|
|
||||||
Clear: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
|
||||||
position: Vec3,
|
|
||||||
rotation: Quat,
|
|
||||||
radius: f32,
|
|
||||||
color: Color,
|
|
||||||
resolution: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Config, Clear> SphereBuilder<'_, '_, '_, Config, Clear>
|
|
||||||
where
|
|
||||||
Config: GizmoConfigGroup,
|
|
||||||
Clear: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
/// Set the number of line-segments per circle for this sphere.
|
|
||||||
pub fn resolution(mut self, resolution: usize) -> Self {
|
|
||||||
self.resolution = resolution;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Config, Clear> Drop for SphereBuilder<'_, '_, '_, Config, Clear>
|
|
||||||
where
|
|
||||||
Config: GizmoConfigGroup,
|
|
||||||
Clear: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if !self.gizmos.enabled {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for axis in Dir3::AXES {
|
|
||||||
self.gizmos
|
|
||||||
.circle(self.position, self.rotation * axis, self.radius, self.color)
|
|
||||||
.resolution(self.resolution);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rect_inner(size: Vec2) -> [Vec2; 4] {
|
fn rect_inner(size: Vec2) -> [Vec2; 4] {
|
||||||
let half_size = size / 2.;
|
let half_size = size / 2.;
|
||||||
let tl = Vec2::new(-half_size.x, half_size.y);
|
let tl = Vec2::new(-half_size.x, half_size.y);
|
||||||
|
|||||||
@ -102,7 +102,7 @@ where
|
|||||||
Config: GizmoConfigGroup,
|
Config: GizmoConfigGroup,
|
||||||
Clear: 'static + Send + Sync,
|
Clear: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
type Output<'a> = () where Self: 'a;
|
type Output<'a> = crate::circles::Ellipse2dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a;
|
||||||
|
|
||||||
fn primitive_2d(
|
fn primitive_2d(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -111,11 +111,7 @@ where
|
|||||||
_angle: f32,
|
_angle: f32,
|
||||||
color: impl Into<Color>,
|
color: impl Into<Color>,
|
||||||
) -> Self::Output<'_> {
|
) -> Self::Output<'_> {
|
||||||
if !self.enabled {
|
self.circle_2d(position, primitive.radius, color)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.circle_2d(position, primitive.radius, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,46 +201,114 @@ where
|
|||||||
Config: GizmoConfigGroup,
|
Config: GizmoConfigGroup,
|
||||||
Clear: 'static + Send + Sync,
|
Clear: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
type Output<'a> = () where Self: 'a;
|
type Output<'a> = crate::circles::Ellipse2dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a;
|
||||||
|
|
||||||
fn primitive_2d(
|
fn primitive_2d<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
primitive: &Ellipse,
|
primitive: &Ellipse,
|
||||||
position: Vec2,
|
position: Vec2,
|
||||||
angle: f32,
|
angle: f32,
|
||||||
color: impl Into<Color>,
|
color: impl Into<Color>,
|
||||||
) -> Self::Output<'_> {
|
) -> Self::Output<'_> {
|
||||||
if !self.enabled {
|
self.ellipse_2d(position, angle, primitive.half_size, color)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ellipse_2d(position, angle, primitive.half_size, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// annulus 2d
|
// annulus 2d
|
||||||
|
|
||||||
|
/// Builder for configuring the drawing options of [`Annulus`].
|
||||||
|
pub struct Annulus2dBuilder<'a, 'w, 's, Config, Clear>
|
||||||
|
where
|
||||||
|
Config: GizmoConfigGroup,
|
||||||
|
Clear: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
||||||
|
position: Vec2,
|
||||||
|
inner_radius: f32,
|
||||||
|
outer_radius: f32,
|
||||||
|
color: Color,
|
||||||
|
inner_resolution: usize,
|
||||||
|
outer_resolution: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Config, Clear> Annulus2dBuilder<'_, '_, '_, Config, Clear>
|
||||||
|
where
|
||||||
|
Config: GizmoConfigGroup,
|
||||||
|
Clear: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
/// Set the number of line-segments for each circle of the annulus.
|
||||||
|
pub fn resolution(mut self, resolution: usize) -> Self {
|
||||||
|
self.outer_resolution = resolution;
|
||||||
|
self.inner_resolution = resolution;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the number of line-segments for the outer circle of the annulus.
|
||||||
|
pub fn outer_resolution(mut self, resolution: usize) -> Self {
|
||||||
|
self.outer_resolution = resolution;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the number of line-segments for the inner circle of the annulus.
|
||||||
|
pub fn inner_resolution(mut self, resolution: usize) -> Self {
|
||||||
|
self.inner_resolution = resolution;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Annulus> for Gizmos<'w, 's, Config, Clear>
|
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Annulus> for Gizmos<'w, 's, Config, Clear>
|
||||||
where
|
where
|
||||||
Config: GizmoConfigGroup,
|
Config: GizmoConfigGroup,
|
||||||
Clear: 'static + Send + Sync,
|
Clear: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
type Output<'a> = () where Self: 'a;
|
type Output<'a> = Annulus2dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a;
|
||||||
|
|
||||||
fn primitive_2d(
|
fn primitive_2d(
|
||||||
&mut self,
|
&mut self,
|
||||||
primitive: &Annulus,
|
primitive: &Annulus,
|
||||||
position: Vec2,
|
position: Vec2,
|
||||||
angle: f32,
|
_angle: f32,
|
||||||
color: impl Into<Color>,
|
color: impl Into<Color>,
|
||||||
) -> Self::Output<'_> {
|
) -> Self::Output<'_> {
|
||||||
if !self.enabled {
|
Annulus2dBuilder {
|
||||||
|
gizmos: self,
|
||||||
|
position,
|
||||||
|
inner_radius: primitive.inner_circle.radius,
|
||||||
|
outer_radius: primitive.outer_circle.radius,
|
||||||
|
color: color.into(),
|
||||||
|
inner_resolution: crate::circles::DEFAULT_CIRCLE_RESOLUTION,
|
||||||
|
outer_resolution: crate::circles::DEFAULT_CIRCLE_RESOLUTION,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Config, Clear> Drop for Annulus2dBuilder<'_, '_, '_, Config, Clear>
|
||||||
|
where
|
||||||
|
Config: GizmoConfigGroup,
|
||||||
|
Clear: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.gizmos.enabled {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let color = color.into();
|
let Annulus2dBuilder {
|
||||||
self.primitive_2d(&primitive.inner_circle, position, angle, color);
|
gizmos,
|
||||||
self.primitive_2d(&primitive.outer_circle, position, angle, color);
|
position,
|
||||||
|
inner_radius,
|
||||||
|
outer_radius,
|
||||||
|
inner_resolution,
|
||||||
|
outer_resolution,
|
||||||
|
color,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
gizmos
|
||||||
|
.circle_2d(*position, *outer_radius, *color)
|
||||||
|
.resolution(*outer_resolution);
|
||||||
|
gizmos
|
||||||
|
.circle_2d(*position, *inner_radius, *color)
|
||||||
|
.resolution(*inner_resolution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,8 +330,7 @@ where
|
|||||||
) -> Self::Output<'_> {
|
) -> Self::Output<'_> {
|
||||||
if !self.enabled {
|
if !self.enabled {
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
let [a, b, c, d] =
|
let [a, b, c, d] =
|
||||||
[(1.0, 0.0), (0.0, 1.0), (-1.0, 0.0), (0.0, -1.0)].map(|(sign_x, sign_y)| {
|
[(1.0, 0.0), (0.0, 1.0), (-1.0, 0.0), (0.0, -1.0)].map(|(sign_x, sign_y)| {
|
||||||
Vec2::new(
|
Vec2::new(
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
//! A module for rendering each of the 3D [`bevy_math::primitives`] with [`Gizmos`].
|
//! A module for rendering each of the 3D [`bevy_math::primitives`] with [`Gizmos`].
|
||||||
|
|
||||||
use super::helpers::*;
|
use super::helpers::*;
|
||||||
use std::f32::consts::TAU;
|
use std::f32::consts::{FRAC_PI_2, PI, TAU};
|
||||||
|
|
||||||
use bevy_color::Color;
|
use bevy_color::Color;
|
||||||
use bevy_math::primitives::{
|
use bevy_math::primitives::{
|
||||||
@ -10,6 +10,7 @@ use bevy_math::primitives::{
|
|||||||
};
|
};
|
||||||
use bevy_math::{Dir3, Quat, Vec3};
|
use bevy_math::{Dir3, Quat, Vec3};
|
||||||
|
|
||||||
|
use crate::circles::SphereBuilder;
|
||||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||||
|
|
||||||
const DEFAULT_RESOLUTION: usize = 5;
|
const DEFAULT_RESOLUTION: usize = 5;
|
||||||
@ -55,41 +56,6 @@ where
|
|||||||
|
|
||||||
// sphere
|
// sphere
|
||||||
|
|
||||||
/// Builder for configuring the drawing options of [`Sphere`].
|
|
||||||
pub struct SphereBuilder<'a, 'w, 's, Config, Clear>
|
|
||||||
where
|
|
||||||
Config: GizmoConfigGroup,
|
|
||||||
Clear: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
// Color of the sphere
|
|
||||||
color: Color,
|
|
||||||
|
|
||||||
// Resolution of the gizmos used to approximate the sphere geometry
|
|
||||||
// The number of vertices used to approximate the sphere geometry.
|
|
||||||
resolution: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Config, Clear> SphereBuilder<'_, '_, '_, Config, Clear>
|
|
||||||
where
|
|
||||||
Config: GizmoConfigGroup,
|
|
||||||
Clear: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
/// Set the number of lines used to approximate the sphere geometry.
|
|
||||||
pub fn resolution(mut self, resolution: usize) -> Self {
|
|
||||||
self.resolution = resolution;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Sphere> for Gizmos<'w, 's, Config, Clear>
|
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Sphere> for Gizmos<'w, 's, Config, Clear>
|
||||||
where
|
where
|
||||||
Config: GizmoConfigGroup,
|
Config: GizmoConfigGroup,
|
||||||
@ -104,59 +70,7 @@ where
|
|||||||
rotation: Quat,
|
rotation: Quat,
|
||||||
color: impl Into<Color>,
|
color: impl Into<Color>,
|
||||||
) -> Self::Output<'_> {
|
) -> Self::Output<'_> {
|
||||||
SphereBuilder {
|
self.sphere(position, rotation, primitive.radius, color)
|
||||||
gizmos: self,
|
|
||||||
radius: primitive.radius,
|
|
||||||
position,
|
|
||||||
rotation,
|
|
||||||
color: color.into(),
|
|
||||||
resolution: DEFAULT_RESOLUTION,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Config, Clear> Drop for SphereBuilder<'_, '_, '_, Config, Clear>
|
|
||||||
where
|
|
||||||
Config: GizmoConfigGroup,
|
|
||||||
Clear: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if !self.gizmos.enabled {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let SphereBuilder {
|
|
||||||
radius,
|
|
||||||
position: center,
|
|
||||||
rotation,
|
|
||||||
color,
|
|
||||||
resolution,
|
|
||||||
..
|
|
||||||
} = self;
|
|
||||||
|
|
||||||
// draws the upper and lower semi spheres
|
|
||||||
[-1.0, 1.0].into_iter().for_each(|sign| {
|
|
||||||
let top = *center + (*rotation * Vec3::Y) * sign * *radius;
|
|
||||||
draw_semi_sphere(
|
|
||||||
self.gizmos,
|
|
||||||
*radius,
|
|
||||||
*resolution,
|
|
||||||
*rotation,
|
|
||||||
*center,
|
|
||||||
top,
|
|
||||||
*color,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// draws one great circle of the sphere
|
|
||||||
draw_circle_3d(
|
|
||||||
self.gizmos,
|
|
||||||
*radius,
|
|
||||||
*resolution,
|
|
||||||
*rotation,
|
|
||||||
*center,
|
|
||||||
*color,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,30 +492,27 @@ where
|
|||||||
resolution,
|
resolution,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let normal = *rotation * Vec3::Y;
|
let normal = Dir3::new_unchecked(*rotation * Vec3::Y);
|
||||||
|
let up = normal.as_vec3() * *half_height;
|
||||||
|
|
||||||
// draw upper and lower circle of the cylinder
|
// draw upper and lower circle of the cylinder
|
||||||
[-1.0, 1.0].into_iter().for_each(|sign| {
|
[-1.0, 1.0].into_iter().for_each(|sign| {
|
||||||
draw_circle_3d(
|
gizmos
|
||||||
gizmos,
|
.circle(*position + sign * up, normal, *radius, *color)
|
||||||
*radius,
|
.resolution(*resolution);
|
||||||
*resolution,
|
|
||||||
*rotation,
|
|
||||||
*position + sign * *half_height * normal,
|
|
||||||
*color,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// draw lines connecting the two cylinder circles
|
// draw lines connecting the two cylinder circles
|
||||||
draw_cylinder_vertical_lines(
|
[Vec3::NEG_X, Vec3::NEG_Z, Vec3::X, Vec3::Z]
|
||||||
gizmos,
|
.into_iter()
|
||||||
*radius,
|
.for_each(|axis| {
|
||||||
*resolution,
|
let axis = *rotation * axis;
|
||||||
*half_height,
|
gizmos.line(
|
||||||
*rotation,
|
*position + up + axis * *radius,
|
||||||
*position,
|
*position - up + axis * *radius,
|
||||||
*color,
|
*color,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,26 +602,57 @@ where
|
|||||||
resolution,
|
resolution,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let normal = *rotation * Vec3::Y;
|
// 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;
|
||||||
|
|
||||||
// draw two semi spheres for the capsule
|
// Draw the vertical lines and the cap semicircles
|
||||||
[1.0, -1.0].into_iter().for_each(|sign| {
|
[Vec3::X, Vec3::Z].into_iter().for_each(|axis| {
|
||||||
let center = *position + sign * *half_length * normal;
|
let normal = *rotation * axis;
|
||||||
let top = center + sign * *radius * normal;
|
|
||||||
draw_semi_sphere(gizmos, *radius, *resolution, *rotation, center, top, *color);
|
gizmos.line(
|
||||||
draw_circle_3d(gizmos, *radius, *resolution, *rotation, center, *color);
|
*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);
|
||||||
});
|
});
|
||||||
|
|
||||||
// connect the two semi spheres with lines
|
|
||||||
draw_cylinder_vertical_lines(
|
|
||||||
gizmos,
|
|
||||||
*radius,
|
|
||||||
*resolution,
|
|
||||||
*half_length,
|
|
||||||
*rotation,
|
|
||||||
*position,
|
|
||||||
*color,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,33 +46,6 @@ pub(crate) fn circle_coordinates(radius: f32, resolution: usize) -> impl Iterato
|
|||||||
.take(resolution)
|
.take(resolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws a semi-sphere.
|
|
||||||
///
|
|
||||||
/// This function draws a semi-sphere at the specified `center` point with the given `rotation`,
|
|
||||||
/// `radius`, and `color`. The `resolution` parameter determines the level of detail, and the `top`
|
|
||||||
/// argument specifies the shape of the semi-sphere's tip.
|
|
||||||
pub(crate) fn draw_semi_sphere<Config, Clear>(
|
|
||||||
gizmos: &mut Gizmos<'_, '_, Config, Clear>,
|
|
||||||
radius: f32,
|
|
||||||
resolution: usize,
|
|
||||||
rotation: Quat,
|
|
||||||
center: Vec3,
|
|
||||||
top: Vec3,
|
|
||||||
color: Color,
|
|
||||||
) where
|
|
||||||
Config: GizmoConfigGroup,
|
|
||||||
Clear: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
circle_coordinates(radius, resolution)
|
|
||||||
.map(|p| Vec3::new(p.x, 0.0, p.y))
|
|
||||||
.map(rotate_then_translate_3d(rotation, center))
|
|
||||||
.for_each(|from| {
|
|
||||||
gizmos
|
|
||||||
.short_arc_3d_between(center, from, top, color)
|
|
||||||
.resolution(resolution / 2);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Draws a circle in 3D space.
|
/// Draws a circle in 3D space.
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
@ -97,28 +70,3 @@ pub(crate) fn draw_circle_3d<Config, Clear>(
|
|||||||
.map(rotate_then_translate_3d(rotation, translation));
|
.map(rotate_then_translate_3d(rotation, translation));
|
||||||
gizmos.linestrip(positions, color);
|
gizmos.linestrip(positions, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the connecting lines of a cylinder between the top circle and the bottom circle.
|
|
||||||
pub(crate) fn draw_cylinder_vertical_lines<Config, Clear>(
|
|
||||||
gizmos: &mut Gizmos<'_, '_, Config, Clear>,
|
|
||||||
radius: f32,
|
|
||||||
resolution: usize,
|
|
||||||
half_height: f32,
|
|
||||||
rotation: Quat,
|
|
||||||
center: Vec3,
|
|
||||||
color: Color,
|
|
||||||
) where
|
|
||||||
Config: GizmoConfigGroup,
|
|
||||||
Clear: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
circle_coordinates(radius, resolution)
|
|
||||||
.map(move |point_2d| {
|
|
||||||
[1.0, -1.0]
|
|
||||||
.map(|sign| sign * half_height)
|
|
||||||
.map(|height| Vec3::new(point_2d.x, height, point_2d.y))
|
|
||||||
})
|
|
||||||
.map(|ps| ps.map(rotate_then_translate_3d(rotation, center)))
|
|
||||||
.for_each(|[start, end]| {
|
|
||||||
gizmos.line(start, end, color);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@ -452,8 +452,10 @@ fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time
|
|||||||
PrimitiveSelected::RectangleAndCuboid => {
|
PrimitiveSelected::RectangleAndCuboid => {
|
||||||
gizmos.primitive_2d(&RECTANGLE, POSITION, angle, color);
|
gizmos.primitive_2d(&RECTANGLE, POSITION, angle, color);
|
||||||
}
|
}
|
||||||
PrimitiveSelected::CircleAndSphere => gizmos.primitive_2d(&CIRCLE, POSITION, angle, color),
|
PrimitiveSelected::CircleAndSphere => {
|
||||||
PrimitiveSelected::Ellipse => gizmos.primitive_2d(&ELLIPSE, POSITION, angle, color),
|
gizmos.primitive_2d(&CIRCLE, POSITION, angle, color);
|
||||||
|
}
|
||||||
|
PrimitiveSelected::Ellipse => drop(gizmos.primitive_2d(&ELLIPSE, POSITION, angle, color)),
|
||||||
PrimitiveSelected::Triangle => gizmos.primitive_2d(&TRIANGLE_2D, POSITION, angle, color),
|
PrimitiveSelected::Triangle => gizmos.primitive_2d(&TRIANGLE_2D, POSITION, angle, color),
|
||||||
PrimitiveSelected::Plane => gizmos.primitive_2d(&PLANE_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::Line => drop(gizmos.primitive_2d(&LINE2D, POSITION, angle, color)),
|
||||||
@ -469,7 +471,7 @@ fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time
|
|||||||
PrimitiveSelected::Cylinder => {}
|
PrimitiveSelected::Cylinder => {}
|
||||||
PrimitiveSelected::Cone => {}
|
PrimitiveSelected::Cone => {}
|
||||||
PrimitiveSelected::ConicalFrustum => {}
|
PrimitiveSelected::ConicalFrustum => {}
|
||||||
PrimitiveSelected::Torus => gizmos.primitive_2d(&ANNULUS, POSITION, angle, color),
|
PrimitiveSelected::Torus => drop(gizmos.primitive_2d(&ANNULUS, POSITION, angle, color)),
|
||||||
PrimitiveSelected::Tetrahedron => {}
|
PrimitiveSelected::Tetrahedron => {}
|
||||||
PrimitiveSelected::Arc => gizmos.primitive_2d(&ARC, POSITION, angle, color),
|
PrimitiveSelected::Arc => gizmos.primitive_2d(&ARC, POSITION, angle, color),
|
||||||
PrimitiveSelected::CircularSector => {
|
PrimitiveSelected::CircularSector => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user