rafx_plugins/features/debug3d/
debug3d_resource.rs

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        // Nothing will draw if we don't have at least 2 points
30        if points.len() > 1 {
31            self.line_lists.push(LineList3D::new(points, color));
32        }
33    }
34
35    // Adds a single polygon
36    pub fn add_line_loop(
37        &mut self,
38        mut points: Vec<glam::Vec3>,
39        color: glam::Vec4,
40    ) {
41        // Nothing will draw if we don't have at least 2 points
42        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    // Takes an X/Y axis pair and center position
59    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            //let position = glam::Vec4::new(fraction.sin() * radius, fraction.cos() * radius, 0.0, 1.0);
76            //let transformed = transform * position;
77            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            // Can't cross the Z axis with the up vector, so special case that here
86            (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    // Takes a normal and center position
95    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        // Draw the vertical rings
115        for index in 0..segments {
116            // Rotate around whole sphere (2pi)
117            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        // Draw the center horizontal ring
125        self.add_circle_xy(
126            center,
127            glam::Vec3::X,
128            glam::Vec3::Y,
129            radius,
130            color,
131            segments,
132        );
133
134        // Draw the off-center horizontal rings
135        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            //let transform = glam::Mat4::from_translation(center + glam::Vec3::new(0.0, 0.0, z_offset));
142            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,      // (position of the pointy bit)
165        base_center: glam::Vec3, // (position of the center of the base of the cone)
166        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    // Returns the draw data, leaving this object in an empty state
327    pub fn take_line_lists(&mut self) -> Vec<LineList3D> {
328        std::mem::replace(&mut self.line_lists, vec![])
329    }
330
331    // Recommended to call every frame to ensure that this doesn't grow unbounded
332    pub fn clear(&mut self) {
333        self.line_lists.clear();
334    }
335}