1 | /**************************************************************************/ |
2 | /* collision_shape_3d_gizmo_plugin.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "collision_shape_3d_gizmo_plugin.h" |
32 | |
33 | #include "core/math/convex_hull.h" |
34 | #include "core/math/geometry_3d.h" |
35 | #include "editor/editor_settings.h" |
36 | #include "editor/editor_undo_redo_manager.h" |
37 | #include "editor/plugins/gizmos/gizmo_3d_helper.h" |
38 | #include "editor/plugins/node_3d_editor_plugin.h" |
39 | #include "scene/3d/collision_shape_3d.h" |
40 | #include "scene/resources/box_shape_3d.h" |
41 | #include "scene/resources/capsule_shape_3d.h" |
42 | #include "scene/resources/concave_polygon_shape_3d.h" |
43 | #include "scene/resources/convex_polygon_shape_3d.h" |
44 | #include "scene/resources/cylinder_shape_3d.h" |
45 | #include "scene/resources/height_map_shape_3d.h" |
46 | #include "scene/resources/separation_ray_shape_3d.h" |
47 | #include "scene/resources/sphere_shape_3d.h" |
48 | #include "scene/resources/world_boundary_shape_3d.h" |
49 | |
50 | CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() { |
51 | helper.instantiate(); |
52 | const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape" ); |
53 | create_material("shape_material" , gizmo_color); |
54 | const float gizmo_value = gizmo_color.get_v(); |
55 | const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65); |
56 | create_material("shape_material_disabled" , gizmo_color_disabled); |
57 | create_handle_material("handles" ); |
58 | } |
59 | |
60 | CollisionShape3DGizmoPlugin::~CollisionShape3DGizmoPlugin() { |
61 | } |
62 | |
63 | bool CollisionShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { |
64 | return Object::cast_to<CollisionShape3D>(p_spatial) != nullptr; |
65 | } |
66 | |
67 | String CollisionShape3DGizmoPlugin::get_gizmo_name() const { |
68 | return "CollisionShape3D" ; |
69 | } |
70 | |
71 | int CollisionShape3DGizmoPlugin::get_priority() const { |
72 | return -1; |
73 | } |
74 | |
75 | String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { |
76 | const CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d()); |
77 | |
78 | Ref<Shape3D> s = cs->get_shape(); |
79 | if (s.is_null()) { |
80 | return "" ; |
81 | } |
82 | |
83 | if (Object::cast_to<SphereShape3D>(*s)) { |
84 | return "Radius" ; |
85 | } |
86 | |
87 | if (Object::cast_to<BoxShape3D>(*s)) { |
88 | return helper->box_get_handle_name(p_id); |
89 | } |
90 | |
91 | if (Object::cast_to<CapsuleShape3D>(*s)) { |
92 | return p_id == 0 ? "Radius" : "Height" ; |
93 | } |
94 | |
95 | if (Object::cast_to<CylinderShape3D>(*s)) { |
96 | return p_id == 0 ? "Radius" : "Height" ; |
97 | } |
98 | |
99 | if (Object::cast_to<SeparationRayShape3D>(*s)) { |
100 | return "Length" ; |
101 | } |
102 | |
103 | return "" ; |
104 | } |
105 | |
106 | Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const { |
107 | CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d()); |
108 | |
109 | Ref<Shape3D> s = cs->get_shape(); |
110 | if (s.is_null()) { |
111 | return Variant(); |
112 | } |
113 | |
114 | if (Object::cast_to<SphereShape3D>(*s)) { |
115 | Ref<SphereShape3D> ss = s; |
116 | return ss->get_radius(); |
117 | } |
118 | |
119 | if (Object::cast_to<BoxShape3D>(*s)) { |
120 | Ref<BoxShape3D> bs = s; |
121 | return bs->get_size(); |
122 | } |
123 | |
124 | if (Object::cast_to<CapsuleShape3D>(*s)) { |
125 | Ref<CapsuleShape3D> cs2 = s; |
126 | return Vector2(cs2->get_radius(), cs2->get_height()); |
127 | } |
128 | |
129 | if (Object::cast_to<CylinderShape3D>(*s)) { |
130 | Ref<CylinderShape3D> cs2 = s; |
131 | return p_id == 0 ? cs2->get_radius() : cs2->get_height(); |
132 | } |
133 | |
134 | if (Object::cast_to<SeparationRayShape3D>(*s)) { |
135 | Ref<SeparationRayShape3D> cs2 = s; |
136 | return cs2->get_length(); |
137 | } |
138 | |
139 | return Variant(); |
140 | } |
141 | |
142 | void CollisionShape3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) { |
143 | helper->initialize_handle_action(get_handle_value(p_gizmo, p_id, p_secondary), p_gizmo->get_node_3d()->get_global_transform()); |
144 | } |
145 | |
146 | void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) { |
147 | CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d()); |
148 | |
149 | Ref<Shape3D> s = cs->get_shape(); |
150 | if (s.is_null()) { |
151 | return; |
152 | } |
153 | |
154 | Vector3 sg[2]; |
155 | helper->get_segment(p_camera, p_point, sg); |
156 | |
157 | if (Object::cast_to<SphereShape3D>(*s)) { |
158 | Ref<SphereShape3D> ss = s; |
159 | Vector3 ra, rb; |
160 | Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb); |
161 | float d = ra.x; |
162 | if (Node3DEditor::get_singleton()->is_snap_enabled()) { |
163 | d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); |
164 | } |
165 | |
166 | if (d < 0.001) { |
167 | d = 0.001; |
168 | } |
169 | |
170 | ss->set_radius(d); |
171 | } |
172 | |
173 | if (Object::cast_to<SeparationRayShape3D>(*s)) { |
174 | Ref<SeparationRayShape3D> rs = s; |
175 | Vector3 ra, rb; |
176 | Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(0, 0, 4096), sg[0], sg[1], ra, rb); |
177 | float d = ra.z; |
178 | if (Node3DEditor::get_singleton()->is_snap_enabled()) { |
179 | d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); |
180 | } |
181 | |
182 | if (d < 0.001) { |
183 | d = 0.001; |
184 | } |
185 | |
186 | rs->set_length(d); |
187 | } |
188 | |
189 | if (Object::cast_to<BoxShape3D>(*s)) { |
190 | Ref<BoxShape3D> bs = s; |
191 | Vector3 size = bs->get_size(); |
192 | Vector3 position; |
193 | helper->box_set_handle(sg, p_id, size, position); |
194 | bs->set_size(size); |
195 | cs->set_global_position(position); |
196 | } |
197 | |
198 | if (Object::cast_to<CapsuleShape3D>(*s)) { |
199 | Vector3 axis; |
200 | axis[p_id == 0 ? 0 : 1] = 1.0; |
201 | Ref<CapsuleShape3D> cs2 = s; |
202 | Vector3 ra, rb; |
203 | Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); |
204 | float d = axis.dot(ra); |
205 | |
206 | if (Node3DEditor::get_singleton()->is_snap_enabled()) { |
207 | d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); |
208 | } |
209 | |
210 | if (d < 0.001) { |
211 | d = 0.001; |
212 | } |
213 | |
214 | if (p_id == 0) { |
215 | cs2->set_radius(d); |
216 | } else if (p_id == 1) { |
217 | cs2->set_height(d * 2.0); |
218 | } |
219 | } |
220 | |
221 | if (Object::cast_to<CylinderShape3D>(*s)) { |
222 | Vector3 axis; |
223 | axis[p_id == 0 ? 0 : 1] = 1.0; |
224 | Ref<CylinderShape3D> cs2 = s; |
225 | Vector3 ra, rb; |
226 | Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); |
227 | float d = axis.dot(ra); |
228 | if (Node3DEditor::get_singleton()->is_snap_enabled()) { |
229 | d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); |
230 | } |
231 | |
232 | if (d < 0.001) { |
233 | d = 0.001; |
234 | } |
235 | |
236 | if (p_id == 0) { |
237 | cs2->set_radius(d); |
238 | } else if (p_id == 1) { |
239 | cs2->set_height(d * 2.0); |
240 | } |
241 | } |
242 | } |
243 | |
244 | void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) { |
245 | CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d()); |
246 | |
247 | Ref<Shape3D> s = cs->get_shape(); |
248 | if (s.is_null()) { |
249 | return; |
250 | } |
251 | |
252 | if (Object::cast_to<SphereShape3D>(*s)) { |
253 | Ref<SphereShape3D> ss = s; |
254 | if (p_cancel) { |
255 | ss->set_radius(p_restore); |
256 | return; |
257 | } |
258 | |
259 | EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); |
260 | ur->create_action(TTR("Change Sphere Shape Radius" )); |
261 | ur->add_do_method(ss.ptr(), "set_radius" , ss->get_radius()); |
262 | ur->add_undo_method(ss.ptr(), "set_radius" , p_restore); |
263 | ur->commit_action(); |
264 | } |
265 | |
266 | if (Object::cast_to<BoxShape3D>(*s)) { |
267 | helper->box_commit_handle(TTR("Change Box Shape Size" ), p_cancel, cs, s.ptr()); |
268 | } |
269 | |
270 | if (Object::cast_to<CapsuleShape3D>(*s)) { |
271 | Ref<CapsuleShape3D> ss = s; |
272 | Vector2 values = p_restore; |
273 | |
274 | if (p_cancel) { |
275 | ss->set_radius(values[0]); |
276 | ss->set_height(values[1]); |
277 | return; |
278 | } |
279 | |
280 | EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); |
281 | if (p_id == 0) { |
282 | ur->create_action(TTR("Change Capsule Shape Radius" )); |
283 | ur->add_do_method(ss.ptr(), "set_radius" , ss->get_radius()); |
284 | } else { |
285 | ur->create_action(TTR("Change Capsule Shape Height" )); |
286 | ur->add_do_method(ss.ptr(), "set_height" , ss->get_height()); |
287 | } |
288 | ur->add_undo_method(ss.ptr(), "set_radius" , values[0]); |
289 | ur->add_undo_method(ss.ptr(), "set_height" , values[1]); |
290 | |
291 | ur->commit_action(); |
292 | } |
293 | |
294 | if (Object::cast_to<CylinderShape3D>(*s)) { |
295 | Ref<CylinderShape3D> ss = s; |
296 | if (p_cancel) { |
297 | if (p_id == 0) { |
298 | ss->set_radius(p_restore); |
299 | } else { |
300 | ss->set_height(p_restore); |
301 | } |
302 | return; |
303 | } |
304 | |
305 | EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); |
306 | if (p_id == 0) { |
307 | ur->create_action(TTR("Change Cylinder Shape Radius" )); |
308 | ur->add_do_method(ss.ptr(), "set_radius" , ss->get_radius()); |
309 | ur->add_undo_method(ss.ptr(), "set_radius" , p_restore); |
310 | } else { |
311 | ur->create_action( |
312 | /// |
313 | |
314 | //////// |
315 | TTR("Change Cylinder Shape Height" )); |
316 | ur->add_do_method(ss.ptr(), "set_height" , ss->get_height()); |
317 | ur->add_undo_method(ss.ptr(), "set_height" , p_restore); |
318 | } |
319 | |
320 | ur->commit_action(); |
321 | } |
322 | |
323 | if (Object::cast_to<SeparationRayShape3D>(*s)) { |
324 | Ref<SeparationRayShape3D> ss = s; |
325 | if (p_cancel) { |
326 | ss->set_length(p_restore); |
327 | return; |
328 | } |
329 | |
330 | EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); |
331 | ur->create_action(TTR("Change Separation Ray Shape Length" )); |
332 | ur->add_do_method(ss.ptr(), "set_length" , ss->get_length()); |
333 | ur->add_undo_method(ss.ptr(), "set_length" , p_restore); |
334 | ur->commit_action(); |
335 | } |
336 | } |
337 | |
338 | void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { |
339 | CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d()); |
340 | |
341 | p_gizmo->clear(); |
342 | |
343 | Ref<Shape3D> s = cs->get_shape(); |
344 | if (s.is_null()) { |
345 | return; |
346 | } |
347 | |
348 | const Ref<Material> material = |
349 | get_material(!cs->is_disabled() ? "shape_material" : "shape_material_disabled" , p_gizmo); |
350 | Ref<Material> handles_material = get_material("handles" ); |
351 | |
352 | if (Object::cast_to<SphereShape3D>(*s)) { |
353 | Ref<SphereShape3D> sp = s; |
354 | float r = sp->get_radius(); |
355 | |
356 | Vector<Vector3> points; |
357 | |
358 | for (int i = 0; i <= 360; i++) { |
359 | float ra = Math::deg_to_rad((float)i); |
360 | float rb = Math::deg_to_rad((float)i + 1); |
361 | Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; |
362 | Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; |
363 | |
364 | points.push_back(Vector3(a.x, 0, a.y)); |
365 | points.push_back(Vector3(b.x, 0, b.y)); |
366 | points.push_back(Vector3(0, a.x, a.y)); |
367 | points.push_back(Vector3(0, b.x, b.y)); |
368 | points.push_back(Vector3(a.x, a.y, 0)); |
369 | points.push_back(Vector3(b.x, b.y, 0)); |
370 | } |
371 | |
372 | Vector<Vector3> collision_segments; |
373 | |
374 | for (int i = 0; i < 64; i++) { |
375 | float ra = i * (Math_TAU / 64.0); |
376 | float rb = (i + 1) * (Math_TAU / 64.0); |
377 | Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r; |
378 | Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r; |
379 | |
380 | collision_segments.push_back(Vector3(a.x, 0, a.y)); |
381 | collision_segments.push_back(Vector3(b.x, 0, b.y)); |
382 | collision_segments.push_back(Vector3(0, a.x, a.y)); |
383 | collision_segments.push_back(Vector3(0, b.x, b.y)); |
384 | collision_segments.push_back(Vector3(a.x, a.y, 0)); |
385 | collision_segments.push_back(Vector3(b.x, b.y, 0)); |
386 | } |
387 | |
388 | p_gizmo->add_lines(points, material); |
389 | p_gizmo->add_collision_segments(collision_segments); |
390 | Vector<Vector3> handles; |
391 | handles.push_back(Vector3(r, 0, 0)); |
392 | p_gizmo->add_handles(handles, handles_material); |
393 | } |
394 | |
395 | if (Object::cast_to<BoxShape3D>(*s)) { |
396 | Ref<BoxShape3D> bs = s; |
397 | Vector<Vector3> lines; |
398 | AABB aabb; |
399 | aabb.position = -bs->get_size() / 2; |
400 | aabb.size = bs->get_size(); |
401 | |
402 | for (int i = 0; i < 12; i++) { |
403 | Vector3 a, b; |
404 | aabb.get_edge(i, a, b); |
405 | lines.push_back(a); |
406 | lines.push_back(b); |
407 | } |
408 | |
409 | const Vector<Vector3> handles = helper->box_get_handles(bs->get_size()); |
410 | |
411 | p_gizmo->add_lines(lines, material); |
412 | p_gizmo->add_collision_segments(lines); |
413 | p_gizmo->add_handles(handles, handles_material); |
414 | } |
415 | |
416 | if (Object::cast_to<CapsuleShape3D>(*s)) { |
417 | Ref<CapsuleShape3D> cs2 = s; |
418 | float radius = cs2->get_radius(); |
419 | float height = cs2->get_height(); |
420 | |
421 | Vector<Vector3> points; |
422 | |
423 | Vector3 d(0, height * 0.5 - radius, 0); |
424 | for (int i = 0; i < 360; i++) { |
425 | float ra = Math::deg_to_rad((float)i); |
426 | float rb = Math::deg_to_rad((float)i + 1); |
427 | Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; |
428 | Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; |
429 | |
430 | points.push_back(Vector3(a.x, 0, a.y) + d); |
431 | points.push_back(Vector3(b.x, 0, b.y) + d); |
432 | |
433 | points.push_back(Vector3(a.x, 0, a.y) - d); |
434 | points.push_back(Vector3(b.x, 0, b.y) - d); |
435 | |
436 | if (i % 90 == 0) { |
437 | points.push_back(Vector3(a.x, 0, a.y) + d); |
438 | points.push_back(Vector3(a.x, 0, a.y) - d); |
439 | } |
440 | |
441 | Vector3 dud = i < 180 ? d : -d; |
442 | |
443 | points.push_back(Vector3(0, a.x, a.y) + dud); |
444 | points.push_back(Vector3(0, b.x, b.y) + dud); |
445 | points.push_back(Vector3(a.y, a.x, 0) + dud); |
446 | points.push_back(Vector3(b.y, b.x, 0) + dud); |
447 | } |
448 | |
449 | p_gizmo->add_lines(points, material); |
450 | |
451 | Vector<Vector3> collision_segments; |
452 | |
453 | for (int i = 0; i < 64; i++) { |
454 | float ra = i * (Math_TAU / 64.0); |
455 | float rb = (i + 1) * (Math_TAU / 64.0); |
456 | Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; |
457 | Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; |
458 | |
459 | collision_segments.push_back(Vector3(a.x, 0, a.y) + d); |
460 | collision_segments.push_back(Vector3(b.x, 0, b.y) + d); |
461 | |
462 | collision_segments.push_back(Vector3(a.x, 0, a.y) - d); |
463 | collision_segments.push_back(Vector3(b.x, 0, b.y) - d); |
464 | |
465 | if (i % 16 == 0) { |
466 | collision_segments.push_back(Vector3(a.x, 0, a.y) + d); |
467 | collision_segments.push_back(Vector3(a.x, 0, a.y) - d); |
468 | } |
469 | |
470 | Vector3 dud = i < 32 ? d : -d; |
471 | |
472 | collision_segments.push_back(Vector3(0, a.x, a.y) + dud); |
473 | collision_segments.push_back(Vector3(0, b.x, b.y) + dud); |
474 | collision_segments.push_back(Vector3(a.y, a.x, 0) + dud); |
475 | collision_segments.push_back(Vector3(b.y, b.x, 0) + dud); |
476 | } |
477 | |
478 | p_gizmo->add_collision_segments(collision_segments); |
479 | |
480 | Vector<Vector3> handles = { |
481 | Vector3(cs2->get_radius(), 0, 0), |
482 | Vector3(0, cs2->get_height() * 0.5, 0) |
483 | }; |
484 | p_gizmo->add_handles(handles, handles_material); |
485 | } |
486 | |
487 | if (Object::cast_to<CylinderShape3D>(*s)) { |
488 | Ref<CylinderShape3D> cs2 = s; |
489 | float radius = cs2->get_radius(); |
490 | float height = cs2->get_height(); |
491 | |
492 | Vector<Vector3> points; |
493 | |
494 | Vector3 d(0, height * 0.5, 0); |
495 | for (int i = 0; i < 360; i++) { |
496 | float ra = Math::deg_to_rad((float)i); |
497 | float rb = Math::deg_to_rad((float)i + 1); |
498 | Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; |
499 | Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; |
500 | |
501 | points.push_back(Vector3(a.x, 0, a.y) + d); |
502 | points.push_back(Vector3(b.x, 0, b.y) + d); |
503 | |
504 | points.push_back(Vector3(a.x, 0, a.y) - d); |
505 | points.push_back(Vector3(b.x, 0, b.y) - d); |
506 | |
507 | if (i % 90 == 0) { |
508 | points.push_back(Vector3(a.x, 0, a.y) + d); |
509 | points.push_back(Vector3(a.x, 0, a.y) - d); |
510 | } |
511 | } |
512 | |
513 | p_gizmo->add_lines(points, material); |
514 | |
515 | Vector<Vector3> collision_segments; |
516 | |
517 | for (int i = 0; i < 64; i++) { |
518 | float ra = i * (Math_TAU / 64.0); |
519 | float rb = (i + 1) * (Math_TAU / 64.0); |
520 | Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius; |
521 | Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius; |
522 | |
523 | collision_segments.push_back(Vector3(a.x, 0, a.y) + d); |
524 | collision_segments.push_back(Vector3(b.x, 0, b.y) + d); |
525 | |
526 | collision_segments.push_back(Vector3(a.x, 0, a.y) - d); |
527 | collision_segments.push_back(Vector3(b.x, 0, b.y) - d); |
528 | |
529 | if (i % 16 == 0) { |
530 | collision_segments.push_back(Vector3(a.x, 0, a.y) + d); |
531 | collision_segments.push_back(Vector3(a.x, 0, a.y) - d); |
532 | } |
533 | } |
534 | |
535 | p_gizmo->add_collision_segments(collision_segments); |
536 | |
537 | Vector<Vector3> handles = { |
538 | Vector3(cs2->get_radius(), 0, 0), |
539 | Vector3(0, cs2->get_height() * 0.5, 0) |
540 | }; |
541 | p_gizmo->add_handles(handles, handles_material); |
542 | } |
543 | |
544 | if (Object::cast_to<WorldBoundaryShape3D>(*s)) { |
545 | Ref<WorldBoundaryShape3D> wbs = s; |
546 | const Plane &p = wbs->get_plane(); |
547 | |
548 | Vector3 n1 = p.get_any_perpendicular_normal(); |
549 | Vector3 n2 = p.normal.cross(n1).normalized(); |
550 | |
551 | Vector3 pface[4] = { |
552 | p.normal * p.d + n1 * 10.0 + n2 * 10.0, |
553 | p.normal * p.d + n1 * 10.0 + n2 * -10.0, |
554 | p.normal * p.d + n1 * -10.0 + n2 * -10.0, |
555 | p.normal * p.d + n1 * -10.0 + n2 * 10.0, |
556 | }; |
557 | |
558 | Vector<Vector3> points = { |
559 | pface[0], |
560 | pface[1], |
561 | pface[1], |
562 | pface[2], |
563 | pface[2], |
564 | pface[3], |
565 | pface[3], |
566 | pface[0], |
567 | p.normal * p.d, |
568 | p.normal * p.d + p.normal * 3 |
569 | }; |
570 | |
571 | p_gizmo->add_lines(points, material); |
572 | p_gizmo->add_collision_segments(points); |
573 | } |
574 | |
575 | if (Object::cast_to<ConvexPolygonShape3D>(*s)) { |
576 | Vector<Vector3> points = Object::cast_to<ConvexPolygonShape3D>(*s)->get_points(); |
577 | |
578 | if (points.size() > 3) { |
579 | Vector<Vector3> varr = Variant(points); |
580 | Geometry3D::MeshData md; |
581 | Error err = ConvexHullComputer::convex_hull(varr, md); |
582 | if (err == OK) { |
583 | Vector<Vector3> points2; |
584 | points2.resize(md.edges.size() * 2); |
585 | for (uint32_t i = 0; i < md.edges.size(); i++) { |
586 | points2.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a]; |
587 | points2.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b]; |
588 | } |
589 | |
590 | p_gizmo->add_lines(points2, material); |
591 | p_gizmo->add_collision_segments(points2); |
592 | } |
593 | } |
594 | } |
595 | |
596 | if (Object::cast_to<ConcavePolygonShape3D>(*s)) { |
597 | Ref<ConcavePolygonShape3D> cs2 = s; |
598 | Ref<ArrayMesh> mesh = cs2->get_debug_mesh(); |
599 | p_gizmo->add_mesh(mesh, material); |
600 | p_gizmo->add_collision_segments(cs2->get_debug_mesh_lines()); |
601 | } |
602 | |
603 | if (Object::cast_to<SeparationRayShape3D>(*s)) { |
604 | Ref<SeparationRayShape3D> rs = s; |
605 | |
606 | Vector<Vector3> points = { |
607 | Vector3(), |
608 | Vector3(0, 0, rs->get_length()) |
609 | }; |
610 | p_gizmo->add_lines(points, material); |
611 | p_gizmo->add_collision_segments(points); |
612 | Vector<Vector3> handles; |
613 | handles.push_back(Vector3(0, 0, rs->get_length())); |
614 | p_gizmo->add_handles(handles, handles_material); |
615 | } |
616 | |
617 | if (Object::cast_to<HeightMapShape3D>(*s)) { |
618 | Ref<HeightMapShape3D> hms = s; |
619 | |
620 | Ref<ArrayMesh> mesh = hms->get_debug_mesh(); |
621 | p_gizmo->add_mesh(mesh, material); |
622 | } |
623 | } |
624 | |