Skip to content

Commit 35cec8b

Browse files
authored
Add Grid gizmos (#11988)
# Objective - Implement grid gizmos, suggestion of #9400 ## Solution - Added `gizmos.grid(...) ` and `gizmos.grid_2d(...)` - The grids may be configured using `.outer_edges(...)` to specify whether to draw the outer border/edges of the grid and `.skew(...)`to specify the skew of the grid along the x or y directions. --- ## Changelog - Added a `grid` module to `bevy_gizmos` containing `gizmos.grid(...) ` and `gizmos.grid_2d(...)` as well as assorted items. - Updated the `2d_gizmos` and `3d_gizmos` examples to use grids. ## Additional The 2D and 3D examples now look like this: <img width="1440" alt="Screenshot 2024-02-20 at 15 09 40" src="https://github.com/bevyengine/bevy/assets/62256001/ce04191e-d839-4faf-a6e3-49b6bb4b922b"> <img width="1440" alt="Screenshot 2024-02-20 at 15 10 07" src="https://github.com/bevyengine/bevy/assets/62256001/317459ba-d452-42eb-ae95-7c84cdbd569b">
1 parent 9ae5ba2 commit 35cec8b

File tree

4 files changed

+237
-0
lines changed

4 files changed

+237
-0
lines changed

crates/bevy_gizmos/src/grid.rs

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
//! Additional [`Gizmos`] Functions -- Grids
2+
//!
3+
//! Includes the implementation of[`Gizmos::grid`] and [`Gizmos::grid_2d`].
4+
//! and assorted support items.
5+
6+
use crate::prelude::{GizmoConfigGroup, Gizmos};
7+
use bevy_math::{Quat, UVec2, Vec2, Vec3};
8+
use bevy_render::color::LegacyColor;
9+
10+
/// A builder returned by [`Gizmos::grid`] and [`Gizmos::grid_2d`]
11+
pub struct GridBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
12+
gizmos: &'a mut Gizmos<'w, 's, T>,
13+
position: Vec3,
14+
rotation: Quat,
15+
spacing: Vec2,
16+
cell_count: UVec2,
17+
skew: Vec2,
18+
outer_edges: bool,
19+
color: LegacyColor,
20+
}
21+
22+
impl<T: GizmoConfigGroup> GridBuilder<'_, '_, '_, T> {
23+
/// Skews the grid by `tan(skew)` in the x direction.
24+
/// `skew` is in radians
25+
pub fn skew_x(mut self, skew: f32) -> Self {
26+
self.skew.x = skew;
27+
self
28+
}
29+
/// Skews the grid by `tan(skew)` in the x direction.
30+
/// `skew` is in radians
31+
pub fn skew_y(mut self, skew: f32) -> Self {
32+
self.skew.y = skew;
33+
self
34+
}
35+
/// Skews the grid by `tan(skew)` in the x and y directions.
36+
/// `skew` is in radians
37+
pub fn skew(mut self, skew: Vec2) -> Self {
38+
self.skew = skew;
39+
self
40+
}
41+
42+
/// Toggle whether the outer edges of the grid should be drawn.
43+
/// By default, the outer edges will not be drawn.
44+
pub fn outer_edges(mut self, outer_edges: bool) -> Self {
45+
self.outer_edges = outer_edges;
46+
self
47+
}
48+
}
49+
50+
impl<T: GizmoConfigGroup> Drop for GridBuilder<'_, '_, '_, T> {
51+
/// Draws a grid, by drawing lines with the stored [`Gizmos`]
52+
fn drop(&mut self) {
53+
if !self.gizmos.enabled {
54+
return;
55+
}
56+
57+
// Offset between two adjacent grid cells along the x/y-axis and accounting for skew.
58+
let dx = Vec3::new(self.spacing.x, self.spacing.x * self.skew.y.tan(), 0.);
59+
let dy = Vec3::new(self.spacing.y * self.skew.x.tan(), self.spacing.y, 0.);
60+
61+
// Bottom-left corner of the grid
62+
let grid_start = self.position
63+
- self.cell_count.x as f32 / 2.0 * dx
64+
- self.cell_count.y as f32 / 2.0 * dy;
65+
66+
let (line_count, vertical_start, horizontal_start) = if self.outer_edges {
67+
(self.cell_count + UVec2::ONE, grid_start, grid_start)
68+
} else {
69+
(
70+
self.cell_count.saturating_sub(UVec2::ONE),
71+
grid_start + dx,
72+
grid_start + dy,
73+
)
74+
};
75+
76+
// Vertical lines
77+
let dline = dy * self.cell_count.y as f32;
78+
for i in 0..line_count.x {
79+
let i = i as f32;
80+
let line_start = vertical_start + i * dx;
81+
let line_end = line_start + dline;
82+
83+
self.gizmos.line(
84+
self.rotation * line_start,
85+
self.rotation * line_end,
86+
self.color,
87+
);
88+
}
89+
90+
// Horizontal lines
91+
let dline = dx * self.cell_count.x as f32;
92+
for i in 0..line_count.y {
93+
let i = i as f32;
94+
let line_start = horizontal_start + i * dy;
95+
let line_end = line_start + dline;
96+
97+
self.gizmos.line(
98+
self.rotation * line_start,
99+
self.rotation * line_end,
100+
self.color,
101+
);
102+
}
103+
}
104+
}
105+
106+
impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
107+
/// Draw a 2D grid in 3D.
108+
///
109+
/// This should be called for each frame the grid needs to be rendered.
110+
///
111+
/// # Arguments
112+
///
113+
/// - `position`: The center point of the grid.
114+
/// - `rotation`: defines the orientation of the grid, by default we assume the grid is contained in a plane parallel to the XY plane.
115+
/// - `cell_count`: defines the amount of cells in the x and y axes
116+
/// - `spacing`: defines the distance between cells along the x and y axes
117+
/// - `color`: color of the grid
118+
///
119+
/// # Builder methods
120+
///
121+
/// - The skew of the grid can be adjusted using the `.skew(...)`, `.skew_x(...)` or `.skew_y(...)` methods. They behave very similar to their CSS equivalents.
122+
/// - The outer edges can be toggled on or off using `.outer_edges(...)`.
123+
///
124+
/// # Example
125+
/// ```
126+
/// # use bevy_gizmos::prelude::*;
127+
/// # use bevy_render::prelude::*;
128+
/// # use bevy_math::prelude::*;
129+
/// fn system(mut gizmos: Gizmos) {
130+
/// gizmos.grid(
131+
/// Vec3::ZERO,
132+
/// Quat::IDENTITY,
133+
/// UVec2::new(10, 10),
134+
/// Vec2::splat(2.),
135+
/// LegacyColor::GREEN
136+
/// )
137+
/// .skew_x(0.25)
138+
/// .outer_edges(true);
139+
/// }
140+
/// # bevy_ecs::system::assert_is_system(system);
141+
/// ```
142+
pub fn grid(
143+
&mut self,
144+
position: Vec3,
145+
rotation: Quat,
146+
cell_count: UVec2,
147+
spacing: Vec2,
148+
color: LegacyColor,
149+
) -> GridBuilder<'_, 'w, 's, T> {
150+
GridBuilder {
151+
gizmos: self,
152+
position,
153+
rotation,
154+
spacing,
155+
cell_count,
156+
skew: Vec2::ZERO,
157+
outer_edges: false,
158+
color,
159+
}
160+
}
161+
162+
/// Draw a grid in 2D.
163+
///
164+
/// This should be called for each frame the grid needs to be rendered.
165+
///
166+
/// # Arguments
167+
///
168+
/// - `position`: The center point of the grid.
169+
/// - `rotation`: defines the orientation of the grid.
170+
/// - `cell_count`: defines the amount of cells in the x and y axes
171+
/// - `spacing`: defines the distance between cells along the x and y axes
172+
/// - `color`: color of the grid
173+
///
174+
/// # Builder methods
175+
///
176+
/// - The skew of the grid can be adjusted using the `.skew(...)`, `.skew_x(...)` or `.skew_y(...)` methods. They behave very similar to their CSS equivalents.
177+
/// - The outer edges can be toggled on or off using `.outer_edges(...)`.
178+
///
179+
/// # Example
180+
/// ```
181+
/// # use bevy_gizmos::prelude::*;
182+
/// # use bevy_render::prelude::*;
183+
/// # use bevy_math::prelude::*;
184+
/// fn system(mut gizmos: Gizmos) {
185+
/// gizmos.grid_2d(
186+
/// Vec2::ZERO,
187+
/// 0.0,
188+
/// UVec2::new(10, 10),
189+
/// Vec2::splat(1.),
190+
/// LegacyColor::GREEN
191+
/// )
192+
/// .skew_x(0.25)
193+
/// .outer_edges(true);
194+
/// }
195+
/// # bevy_ecs::system::assert_is_system(system);
196+
/// ```
197+
pub fn grid_2d(
198+
&mut self,
199+
position: Vec2,
200+
rotation: f32,
201+
cell_count: UVec2,
202+
spacing: Vec2,
203+
color: LegacyColor,
204+
) -> GridBuilder<'_, 'w, 's, T> {
205+
GridBuilder {
206+
gizmos: self,
207+
position: position.extend(0.),
208+
rotation: Quat::from_rotation_z(rotation),
209+
spacing,
210+
cell_count,
211+
skew: Vec2::ZERO,
212+
outer_edges: false,
213+
color,
214+
}
215+
}
216+
}

crates/bevy_gizmos/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub mod arrows;
3030
pub mod circles;
3131
pub mod config;
3232
pub mod gizmos;
33+
pub mod grid;
3334
pub mod primitives;
3435

3536
#[cfg(feature = "bevy_sprite")]

examples/gizmos/2d_gizmos.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ fn draw_example_collection(
4141
gizmos.line_2d(Vec2::Y * -sin, Vec2::splat(-80.), LegacyColor::RED);
4242
gizmos.ray_2d(Vec2::Y * sin, Vec2::splat(80.), LegacyColor::GREEN);
4343

44+
gizmos
45+
.grid_2d(
46+
Vec2::ZERO,
47+
0.0,
48+
UVec2::new(16, 12),
49+
Vec2::new(60., 60.),
50+
// Light gray
51+
LegacyColor::rgb(0.65, 0.65, 0.65),
52+
)
53+
.outer_edges(true);
54+
4455
// Triangle
4556
gizmos.linestrip_gradient_2d([
4657
(Vec2::Y * 300., LegacyColor::BLUE),

examples/gizmos/3d_gizmos.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ fn draw_example_collection(
8686
mut my_gizmos: Gizmos<MyRoundGizmos>,
8787
time: Res<Time>,
8888
) {
89+
gizmos.grid(
90+
Vec3::ZERO,
91+
Quat::from_rotation_x(PI / 2.),
92+
UVec2::splat(20),
93+
Vec2::new(2., 2.),
94+
// Light gray
95+
LegacyColor::rgb(0.65, 0.65, 0.65),
96+
);
97+
8998
gizmos.cuboid(
9099
Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.25)),
91100
LegacyColor::BLACK,

0 commit comments

Comments
 (0)