Improve the gizmo for Plane3d, reusing grid (#14650)

# Objective

With the current implementation of `Plane3d` gizmos, it's really hard to
get a good feeling for big planes. Usually I tend to add more axes as a
user but that doesn't scale well and is pretty wasteful. It's hard to
recognize the plane in the distance here. Especially if there would've
been other rendered objects in the scene


![image](https://github.com/user-attachments/assets/b65b7015-c08c-46d7-aa27-c7c0d49b2021)

## Solution

- Since we got grid gizmos in the mean time, I went ahead and just
reused them here.

## Testing

I added an instance of the new `Plane3D` to the `3d_gizmos.rs` example.
If you want to look at it you need to look around a bit. I didn't
position it in the center since that was too crowded already.

---

## Showcase


![image](https://github.com/user-attachments/assets/e4982afe-7296-416c-9801-7dd85cd975c1)

## Migration Guide

The optional builder methods on 

```rust

gizmos.primitive_3d(&Plane3d { }, ...);

```

changed from

- `segment_length`
- `segment_count`
- `axis_count`

to 

- `cell_count`
- `spacing`
This commit is contained in:
Robert Walter 2024-08-29 15:51:36 +00:00 committed by GitHub
parent e600e2c1b1
commit 565324daa3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 51 deletions

View file

@ -182,6 +182,8 @@ where
/// ///
/// This should be called for each frame the grid needs to be rendered. /// This should be called for each frame the grid needs to be rendered.
/// ///
/// The grid's default orientation aligns with the XY-plane.
///
/// # Arguments /// # Arguments
/// ///
/// - `isometry` defines the translation and rotation of the grid. /// - `isometry` defines the translation and rotation of the grid.

View file

@ -1,14 +1,13 @@
//! 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 bevy_color::Color; use bevy_color::Color;
use bevy_math::primitives::{ use bevy_math::primitives::{
BoxedPolyline3d, Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, Line3d, Plane3d, BoxedPolyline3d, Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, Line3d, Plane3d,
Polyline3d, Primitive3d, Segment3d, Sphere, Tetrahedron, Torus, Triangle3d, Polyline3d, Primitive3d, Segment3d, Sphere, Tetrahedron, Torus, Triangle3d,
}; };
use bevy_math::{Dir3, Isometry3d, Quat, Vec3}; use bevy_math::{Dir3, Isometry3d, Quat, UVec2, Vec2, Vec3};
use crate::circles::SphereBuilder; use crate::circles::SphereBuilder;
use crate::prelude::{GizmoConfigGroup, Gizmos}; use crate::prelude::{GizmoConfigGroup, Gizmos};
@ -83,19 +82,17 @@ where
{ {
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
// direction of the normal orthogonal to the plane // Direction of the normal orthogonal to the plane
normal: Dir3, normal: Dir3,
isometry: Isometry3d, isometry: Isometry3d,
// Color of the plane // Color of the plane
color: Color, color: Color,
// Number of axis to hint the plane // Defines the amount of cells in the x and y axes
axis_count: u32, cell_count: UVec2,
// Number of segments used to hint the plane // Defines the distance between cells along the x and y axes
segment_count: u32, spacing: Vec2,
// Length of segments used to hint the plane
segment_length: f32,
} }
impl<Config, Clear> Plane3dBuilder<'_, '_, '_, Config, Clear> impl<Config, Clear> Plane3dBuilder<'_, '_, '_, Config, Clear>
@ -103,21 +100,15 @@ where
Config: GizmoConfigGroup, Config: GizmoConfigGroup,
Clear: 'static + Send + Sync, Clear: 'static + Send + Sync,
{ {
/// Set the number of segments used to hint the plane. /// Set the number of cells in the x and y axes direction.
pub fn segment_count(mut self, count: u32) -> Self { pub fn cell_count(mut self, cell_count: UVec2) -> Self {
self.segment_count = count; self.cell_count = cell_count;
self self
} }
/// Set the length of segments used to hint the plane. /// Set the distance between cells along the x and y axes.
pub fn segment_length(mut self, length: f32) -> Self { pub fn spacing(mut self, spacing: Vec2) -> Self {
self.segment_length = length; self.spacing = spacing;
self
}
/// Set the number of axis used to hint the plane.
pub fn axis_count(mut self, count: u32) -> Self {
self.axis_count = count;
self self
} }
} }
@ -140,9 +131,8 @@ where
normal: primitive.normal, normal: primitive.normal,
isometry, isometry,
color: color.into(), color: color.into(),
axis_count: 4, cell_count: UVec2::splat(3),
segment_count: 3, spacing: Vec2::splat(1.0),
segment_length: 0.25,
} }
} }
} }
@ -157,35 +147,16 @@ where
return; return;
} }
// draws the normal
self.gizmos self.gizmos
.primitive_3d(&self.normal, self.isometry, self.color); .primitive_3d(&self.normal, self.isometry, self.color);
// the default orientation of the grid is Z-up
// draws the axes let rot = Quat::from_rotation_arc(Vec3::Z, self.normal.as_vec3());
// get rotation for each direction self.gizmos.grid(
let normals_normal = self.normal.any_orthonormal_vector(); Isometry3d::new(self.isometry.translation, self.isometry.rotation * rot),
(0..self.axis_count) self.cell_count,
.map(|i| i as f32 * (1.0 / self.axis_count as f32) * TAU) self.spacing,
.map(|angle| Quat::from_axis_angle(self.normal.as_vec3(), angle)) self.color,
.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)
.take(self.segment_count as usize)
.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);
});
} }
} }

View file

@ -97,6 +97,21 @@ fn draw_example_collection(
); );
gizmos.sphere(Isometry3d::from_translation(Vec3::ONE * 10.0), 1.0, PURPLE); gizmos.sphere(Isometry3d::from_translation(Vec3::ONE * 10.0), 1.0, PURPLE);
gizmos
.primitive_3d(
&Plane3d {
normal: Dir3::Y,
half_size: Vec2::splat(1.0),
},
Isometry3d::new(
Vec3::ONE * 4.0 + Vec2::from(time.elapsed_seconds().sin_cos()).extend(0.0),
Quat::from_rotation_x(PI / 2. + time.elapsed_seconds()),
),
GREEN,
)
.cell_count(UVec2::new(5, 10))
.spacing(Vec2::new(0.2, 0.1));
gizmos.cuboid( gizmos.cuboid(
Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.25)), Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.25)),
BLACK, BLACK,