gpu_particles_collision_3d_gizmo_plugin.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /**************************************************************************/
  2. /* gpu_particles_collision_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. #include "gpu_particles_collision_3d_gizmo_plugin.h"
  31. #include "editor/editor_settings.h"
  32. #include "editor/editor_undo_redo_manager.h"
  33. #include "editor/plugins/gizmos/gizmo_3d_helper.h"
  34. #include "editor/plugins/node_3d_editor_plugin.h"
  35. #include "scene/3d/gpu_particles_collision_3d.h"
  36. GPUParticlesCollision3DGizmoPlugin::GPUParticlesCollision3DGizmoPlugin() {
  37. helper.instantiate();
  38. Color gizmo_color_attractor = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particle_attractor");
  39. create_material("shape_material_attractor", gizmo_color_attractor);
  40. gizmo_color_attractor.a = 0.15;
  41. create_material("shape_material_attractor_internal", gizmo_color_attractor);
  42. Color gizmo_color_collision = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particle_collision");
  43. create_material("shape_material_collision", gizmo_color_collision);
  44. gizmo_color_collision.a = 0.15;
  45. create_material("shape_material_collision_internal", gizmo_color_collision);
  46. create_handle_material("handles");
  47. }
  48. GPUParticlesCollision3DGizmoPlugin::~GPUParticlesCollision3DGizmoPlugin() {
  49. }
  50. bool GPUParticlesCollision3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
  51. return (Object::cast_to<GPUParticlesCollision3D>(p_spatial) != nullptr) || (Object::cast_to<GPUParticlesAttractor3D>(p_spatial) != nullptr);
  52. }
  53. String GPUParticlesCollision3DGizmoPlugin::get_gizmo_name() const {
  54. return "GPUParticlesCollision3D";
  55. }
  56. int GPUParticlesCollision3DGizmoPlugin::get_priority() const {
  57. return -1;
  58. }
  59. String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
  60. const Node3D *cs = p_gizmo->get_node_3d();
  61. if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
  62. return "Radius";
  63. }
  64. if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
  65. return helper->box_get_handle_name(p_id);
  66. }
  67. return "";
  68. }
  69. Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
  70. const Node3D *cs = p_gizmo->get_node_3d();
  71. if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
  72. return p_gizmo->get_node_3d()->call("get_radius");
  73. }
  74. if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
  75. return Vector3(p_gizmo->get_node_3d()->call("get_size"));
  76. }
  77. return Variant();
  78. }
  79. void GPUParticlesCollision3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
  80. helper->initialize_handle_action(get_handle_value(p_gizmo, p_id, p_secondary), p_gizmo->get_node_3d()->get_global_transform());
  81. }
  82. void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
  83. Node3D *sn = p_gizmo->get_node_3d();
  84. Vector3 sg[2];
  85. helper->get_segment(p_camera, p_point, sg);
  86. if (Object::cast_to<GPUParticlesCollisionSphere3D>(sn) || Object::cast_to<GPUParticlesAttractorSphere3D>(sn)) {
  87. Vector3 ra, rb;
  88. Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
  89. float d = ra.x;
  90. if (Node3DEditor::get_singleton()->is_snap_enabled()) {
  91. d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
  92. }
  93. if (d < 0.001) {
  94. d = 0.001;
  95. }
  96. sn->call("set_radius", d);
  97. }
  98. if (Object::cast_to<GPUParticlesCollisionBox3D>(sn) || Object::cast_to<GPUParticlesAttractorBox3D>(sn) || Object::cast_to<GPUParticlesAttractorVectorField3D>(sn) || Object::cast_to<GPUParticlesCollisionSDF3D>(sn) || Object::cast_to<GPUParticlesCollisionHeightField3D>(sn)) {
  99. Vector3 size = sn->call("get_size");
  100. Vector3 position;
  101. helper->box_set_handle(sg, p_id, size, position);
  102. sn->call("set_size", size);
  103. sn->set_global_position(position);
  104. }
  105. }
  106. void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
  107. Node3D *sn = p_gizmo->get_node_3d();
  108. if (Object::cast_to<GPUParticlesCollisionSphere3D>(sn) || Object::cast_to<GPUParticlesAttractorSphere3D>(sn)) {
  109. if (p_cancel) {
  110. sn->call("set_radius", p_restore);
  111. return;
  112. }
  113. EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
  114. ur->create_action(TTR("Change Radius"));
  115. ur->add_do_method(sn, "set_radius", sn->call("get_radius"));
  116. ur->add_undo_method(sn, "set_radius", p_restore);
  117. ur->commit_action();
  118. }
  119. if (Object::cast_to<GPUParticlesCollisionBox3D>(sn) || Object::cast_to<GPUParticlesAttractorBox3D>(sn) || Object::cast_to<GPUParticlesAttractorVectorField3D>(sn) || Object::cast_to<GPUParticlesCollisionSDF3D>(sn) || Object::cast_to<GPUParticlesCollisionHeightField3D>(sn)) {
  120. helper->box_commit_handle("Change Box Shape Size", p_cancel, sn);
  121. }
  122. }
  123. void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
  124. Node3D *cs = p_gizmo->get_node_3d();
  125. p_gizmo->clear();
  126. Ref<Material> material;
  127. Ref<Material> material_internal;
  128. if (Object::cast_to<GPUParticlesAttractor3D>(cs)) {
  129. material = get_material("shape_material_attractor", p_gizmo);
  130. material_internal = get_material("shape_material_attractor_internal", p_gizmo);
  131. } else {
  132. material = get_material("shape_material_collision", p_gizmo);
  133. material_internal = get_material("shape_material_collision_internal", p_gizmo);
  134. }
  135. const Ref<Material> handles_material = get_material("handles");
  136. if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
  137. float r = cs->call("get_radius");
  138. Vector<Vector3> points;
  139. for (int i = 0; i <= 360; i++) {
  140. float ra = Math::deg_to_rad((float)i);
  141. float rb = Math::deg_to_rad((float)i + 1);
  142. Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
  143. Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
  144. points.push_back(Vector3(a.x, 0, a.y));
  145. points.push_back(Vector3(b.x, 0, b.y));
  146. points.push_back(Vector3(0, a.x, a.y));
  147. points.push_back(Vector3(0, b.x, b.y));
  148. points.push_back(Vector3(a.x, a.y, 0));
  149. points.push_back(Vector3(b.x, b.y, 0));
  150. }
  151. Vector<Vector3> collision_segments;
  152. for (int i = 0; i < 64; i++) {
  153. float ra = i * (Math_TAU / 64.0);
  154. float rb = (i + 1) * (Math_TAU / 64.0);
  155. Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
  156. Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
  157. collision_segments.push_back(Vector3(a.x, 0, a.y));
  158. collision_segments.push_back(Vector3(b.x, 0, b.y));
  159. collision_segments.push_back(Vector3(0, a.x, a.y));
  160. collision_segments.push_back(Vector3(0, b.x, b.y));
  161. collision_segments.push_back(Vector3(a.x, a.y, 0));
  162. collision_segments.push_back(Vector3(b.x, b.y, 0));
  163. }
  164. p_gizmo->add_lines(points, material);
  165. p_gizmo->add_collision_segments(collision_segments);
  166. Vector<Vector3> handles;
  167. handles.push_back(Vector3(r, 0, 0));
  168. p_gizmo->add_handles(handles, handles_material);
  169. }
  170. if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
  171. Vector<Vector3> lines;
  172. AABB aabb;
  173. aabb.size = cs->call("get_size").operator Vector3();
  174. aabb.position = aabb.size / -2;
  175. for (int i = 0; i < 12; i++) {
  176. Vector3 a, b;
  177. aabb.get_edge(i, a, b);
  178. lines.push_back(a);
  179. lines.push_back(b);
  180. }
  181. Vector<Vector3> handles = helper->box_get_handles(aabb.size);
  182. p_gizmo->add_lines(lines, material);
  183. p_gizmo->add_collision_segments(lines);
  184. p_gizmo->add_handles(handles, handles_material);
  185. GPUParticlesCollisionSDF3D *col_sdf = Object::cast_to<GPUParticlesCollisionSDF3D>(cs);
  186. if (col_sdf) {
  187. static const int subdivs[GPUParticlesCollisionSDF3D::RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
  188. int subdiv = subdivs[col_sdf->get_resolution()];
  189. float cell_size = aabb.get_longest_axis_size() / subdiv;
  190. lines.clear();
  191. for (int i = 1; i < subdiv; i++) {
  192. for (int j = 0; j < 3; j++) {
  193. if (cell_size * i > aabb.size[j]) {
  194. continue;
  195. }
  196. int j_n1 = (j + 1) % 3;
  197. int j_n2 = (j + 2) % 3;
  198. for (int k = 0; k < 4; k++) {
  199. Vector3 from = aabb.position, to = aabb.position;
  200. from[j] += cell_size * i;
  201. to[j] += cell_size * i;
  202. if (k & 1) {
  203. to[j_n1] += aabb.size[j_n1];
  204. } else {
  205. to[j_n2] += aabb.size[j_n2];
  206. }
  207. if (k & 2) {
  208. from[j_n1] += aabb.size[j_n1];
  209. from[j_n2] += aabb.size[j_n2];
  210. }
  211. lines.push_back(from);
  212. lines.push_back(to);
  213. }
  214. }
  215. }
  216. p_gizmo->add_lines(lines, material_internal);
  217. }
  218. }
  219. }