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.
///
/// The grid's default orientation aligns with the XY-plane.
///
/// # Arguments
///
/// - `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`].
use super::helpers::*;
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, Isometry3d, Quat, Vec3};
use bevy_math::{Dir3, Isometry3d, Quat, UVec2, Vec2, Vec3};
use crate::circles::SphereBuilder;
use crate::prelude::{GizmoConfigGroup, Gizmos};
@ -83,19 +82,17 @@ where
{
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,
isometry: Isometry3d,
// Color of the plane
color: Color,
// Number of axis to hint the plane
axis_count: u32,
// Number of segments used to hint the plane
segment_count: u32,
// Length of segments used to hint the plane
segment_length: f32,
// Defines the amount of cells in the x and y axes
cell_count: UVec2,
// Defines the distance between cells along the x and y axes
spacing: Vec2,
}
impl<Config, Clear> Plane3dBuilder<'_, '_, '_, Config, Clear>
@ -103,21 +100,15 @@ where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
/// Set the number of segments used to hint the plane.
pub fn segment_count(mut self, count: u32) -> Self {
self.segment_count = count;
/// Set the number of cells in the x and y axes direction.
pub fn cell_count(mut self, cell_count: UVec2) -> Self {
self.cell_count = cell_count;
self
}
/// Set the length of segments used to hint the plane.
pub fn segment_length(mut self, length: f32) -> Self {
self.segment_length = length;
self
}
/// Set the number of axis used to hint the plane.
pub fn axis_count(mut self, count: u32) -> Self {
self.axis_count = count;
/// Set the distance between cells along the x and y axes.
pub fn spacing(mut self, spacing: Vec2) -> Self {
self.spacing = spacing;
self
}
}
@ -140,9 +131,8 @@ where
normal: primitive.normal,
isometry,
color: color.into(),
axis_count: 4,
segment_count: 3,
segment_length: 0.25,
cell_count: UVec2::splat(3),
spacing: Vec2::splat(1.0),
}
}
}
@ -157,35 +147,16 @@ where
return;
}
// draws the normal
self.gizmos
.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(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)
.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);
});
// the default orientation of the grid is Z-up
let rot = Quat::from_rotation_arc(Vec3::Z, self.normal.as_vec3());
self.gizmos.grid(
Isometry3d::new(self.isometry.translation, self.isometry.rotation * rot),
self.cell_count,
self.spacing,
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
.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(
Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.25)),
BLACK,