1pub struct LineList3D {
2 pub points: Vec<glam::Vec3>,
3 pub color: glam::Vec4,
4}
5
6impl LineList3D {
7 pub fn new(
8 points: Vec<glam::Vec3>,
9 color: glam::Vec4,
10 ) -> Self {
11 LineList3D { points, color }
12 }
13}
14
15pub struct Debug3DResource {
16 line_lists: Vec<LineList3D>,
17}
18
19impl Debug3DResource {
20 pub fn new() -> Self {
21 Debug3DResource { line_lists: vec![] }
22 }
23
24 pub fn add_line_strip(
25 &mut self,
26 points: Vec<glam::Vec3>,
27 color: glam::Vec4,
28 ) {
29 if points.len() > 1 {
31 self.line_lists.push(LineList3D::new(points, color));
32 }
33 }
34
35 pub fn add_line_loop(
37 &mut self,
38 mut points: Vec<glam::Vec3>,
39 color: glam::Vec4,
40 ) {
41 if points.len() > 1 {
43 points.push(points[0]);
44 self.add_line_strip(points, color);
45 }
46 }
47
48 pub fn add_line(
49 &mut self,
50 p0: glam::Vec3,
51 p1: glam::Vec3,
52 color: glam::Vec4,
53 ) {
54 let points = vec![p0, p1];
55 self.add_line_strip(points, color);
56 }
57
58 pub fn add_circle_xy(
60 &mut self,
61 center: glam::Vec3,
62 x_dir: glam::Vec3,
63 y_dir: glam::Vec3,
64 radius: f32,
65 color: glam::Vec4,
66 segments: u32,
67 ) {
68 let x_dir = x_dir * radius;
69 let y_dir = y_dir * radius;
70
71 let mut points = Vec::with_capacity(segments as usize + 1);
72 for index in 0..segments {
73 let fraction = (index as f32 / segments as f32) * std::f32::consts::PI * 2.0;
74
75 points.push(center + (fraction.cos() * x_dir) + (fraction.sin() * y_dir));
78 }
79
80 self.add_line_loop(points, color);
81 }
82
83 pub fn normal_to_xy(normal: glam::Vec3) -> (glam::Vec3, glam::Vec3) {
84 if normal.dot(glam::Vec3::Z).abs() > 0.9999 {
85 (glam::Vec3::X, glam::Vec3::Y)
87 } else {
88 let x_dir = normal.cross(glam::Vec3::Z);
89 let y_dir = x_dir.cross(normal);
90 (x_dir, y_dir)
91 }
92 }
93
94 pub fn add_circle(
96 &mut self,
97 center: glam::Vec3,
98 normal: glam::Vec3,
99 radius: f32,
100 color: glam::Vec4,
101 segments: u32,
102 ) {
103 let (x_dir, y_dir) = Self::normal_to_xy(normal);
104 self.add_circle_xy(center, x_dir, y_dir, radius, color, segments);
105 }
106
107 pub fn add_sphere(
108 &mut self,
109 center: glam::Vec3,
110 radius: f32,
111 color: glam::Vec4,
112 segments: u32,
113 ) {
114 for index in 0..segments {
116 let fraction = (index as f32 / segments as f32) * std::f32::consts::PI * 2.0;
118 let x_dir = glam::Vec3::new(fraction.cos(), fraction.sin(), 0.0);
119 let y_dir = glam::Vec3::Z;
120
121 self.add_circle_xy(center, x_dir, y_dir, radius, color, segments);
122 }
123
124 self.add_circle_xy(
126 center,
127 glam::Vec3::X,
128 glam::Vec3::Y,
129 radius,
130 color,
131 segments,
132 );
133
134 for index in 1..(segments / 2) {
136 let fraction = (index as f32 / segments as f32) * std::f32::consts::PI * 2.0;
137
138 let r = radius * fraction.cos();
139 let z_offset = radius * fraction.sin() * glam::Vec3::Z;
140
141 self.add_circle_xy(
143 center + z_offset,
144 glam::Vec3::X,
145 glam::Vec3::Y,
146 r,
147 color,
148 segments,
149 );
150
151 self.add_circle_xy(
152 center - z_offset,
153 glam::Vec3::X,
154 glam::Vec3::Y,
155 r,
156 color,
157 segments,
158 );
159 }
160 }
161
162 pub fn add_cone(
163 &mut self,
164 vertex: glam::Vec3, base_center: glam::Vec3, radius: f32,
167 color: glam::Vec4,
168 segments: u32,
169 ) {
170 let base_to_vertex = vertex - base_center;
171 let base_to_vertex_normal = base_to_vertex.normalize();
172 let (x_dir, y_dir) = Self::normal_to_xy(base_to_vertex_normal);
173 for index in 0..segments {
174 let fraction = index as f32 / segments as f32;
175
176 let center = base_center + base_to_vertex * fraction;
177 self.add_circle_xy(
178 center,
179 x_dir,
180 y_dir,
181 radius * (1.0 - fraction),
182 color,
183 segments,
184 );
185 }
186
187 for index in 0..segments / 2 {
188 let fraction = (index as f32 / (segments / 2) as f32) * std::f32::consts::PI;
189 let offset = ((x_dir * fraction.cos()) + (y_dir * fraction.sin())) * radius;
190
191 let p0 = base_center + offset;
192 let p1 = vertex;
193 let p2 = base_center - offset;
194 self.add_line_strip(vec![p0, p1, p2], color);
195 }
196 }
197
198 pub fn add_aabb(
199 &mut self,
200 min: glam::Vec3,
201 max: glam::Vec3,
202 color: glam::Vec4,
203 ) {
204 self.add_line(
205 glam::Vec3::new(min.x, min.y, min.z),
206 glam::Vec3::new(max.x, min.y, min.z),
207 color,
208 );
209 self.add_line(
210 glam::Vec3::new(min.x, min.y, min.z),
211 glam::Vec3::new(min.x, max.y, min.z),
212 color,
213 );
214 self.add_line(
215 glam::Vec3::new(min.x, min.y, min.z),
216 glam::Vec3::new(min.x, min.y, max.z),
217 color,
218 );
219
220 self.add_line(
221 glam::Vec3::new(max.x, max.y, max.z),
222 glam::Vec3::new(min.x, max.y, max.z),
223 color,
224 );
225 self.add_line(
226 glam::Vec3::new(max.x, max.y, max.z),
227 glam::Vec3::new(max.x, min.y, max.z),
228 color,
229 );
230 self.add_line(
231 glam::Vec3::new(max.x, max.y, max.z),
232 glam::Vec3::new(max.x, max.y, min.z),
233 color,
234 );
235
236 self.add_line(
237 glam::Vec3::new(max.x, min.y, min.z),
238 glam::Vec3::new(max.x, max.y, min.z),
239 color,
240 );
241 self.add_line(
242 glam::Vec3::new(max.x, min.y, min.z),
243 glam::Vec3::new(max.x, min.y, max.z),
244 color,
245 );
246
247 self.add_line(
248 glam::Vec3::new(min.x, max.y, min.z),
249 glam::Vec3::new(max.x, max.y, min.z),
250 color,
251 );
252 self.add_line(
253 glam::Vec3::new(min.x, max.y, min.z),
254 glam::Vec3::new(min.x, max.y, max.z),
255 color,
256 );
257
258 self.add_line(
259 glam::Vec3::new(min.x, min.y, max.z),
260 glam::Vec3::new(max.x, min.y, max.z),
261 color,
262 );
263 self.add_line(
264 glam::Vec3::new(min.x, min.y, max.z),
265 glam::Vec3::new(min.x, max.y, max.z),
266 color,
267 );
268 }
269
270 pub fn add_axis_aligned_grid(
271 &mut self,
272 step_distance: f32,
273 ) {
274 const GRID_LINE_AXIS_COLOR_INTENSITY: f32 = 0.25;
275 const GRID_LINE_MAJOR_STEP_COLOR_INTENSITY: f32 = 0.1;
276 const GRID_LINE_MINOR_STEP_COLOR_INTENSITY: f32 = 0.025;
277 const GRID_LINE_MAJOR_STEP_COUNT: i32 = 10;
278 const GRID_LINE_MINOR_STEP_COUNT: i32 = 10;
279 const GRID_LINE_TOTAL_STEP_COUNT: i32 =
280 GRID_LINE_MAJOR_STEP_COUNT * GRID_LINE_MINOR_STEP_COUNT;
281
282 let grid_center = glam::Vec3::ZERO;
283 for i in -GRID_LINE_TOTAL_STEP_COUNT..=GRID_LINE_TOTAL_STEP_COUNT {
284 if i == 0 {
285 continue;
286 }
287
288 let line_color = if (i.abs() % GRID_LINE_MINOR_STEP_COUNT) == 0 {
289 glam::Vec3::splat(GRID_LINE_MAJOR_STEP_COLOR_INTENSITY).extend(1.0)
290 } else {
291 glam::Vec3::splat(GRID_LINE_MINOR_STEP_COLOR_INTENSITY).extend(1.0)
292 };
293
294 let offset_y = glam::Vec3::Y * (i as f32 * step_distance) + grid_center;
295 self.add_line(
296 glam::Vec3::X * -1000.0 + offset_y,
297 glam::Vec3::X * 1000.0 + offset_y,
298 line_color,
299 );
300
301 let offset_x = glam::Vec3::X * (i as f32 * step_distance) + grid_center;
302 self.add_line(
303 glam::Vec3::Y * -1000.0 + offset_x,
304 glam::Vec3::Y * 1000.0 + offset_x,
305 line_color,
306 );
307 }
308
309 self.add_line(
310 glam::Vec3::X * -1000.0 + grid_center,
311 glam::Vec3::X * 1000.0 + grid_center,
312 (glam::Vec3::X * GRID_LINE_AXIS_COLOR_INTENSITY).extend(1.0),
313 );
314 self.add_line(
315 glam::Vec3::Y * -1000.0 + grid_center,
316 glam::Vec3::Y * 1000.0 + grid_center,
317 (glam::Vec3::Y * GRID_LINE_AXIS_COLOR_INTENSITY).extend(1.0),
318 );
319 self.add_line(
320 glam::Vec3::Z * -1000.0 + grid_center,
321 glam::Vec3::Z * 1000.0 + grid_center,
322 (glam::Vec3::Z * GRID_LINE_AXIS_COLOR_INTENSITY).extend(1.0),
323 );
324 }
325
326 pub fn take_line_lists(&mut self) -> Vec<LineList3D> {
328 std::mem::replace(&mut self.line_lists, vec![])
329 }
330
331 pub fn clear(&mut self) {
333 self.line_lists.clear();
334 }
335}