gpu_particles_collision_3d_gizmo_plugin.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. bool GPUParticlesCollision3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
  49. return (Object::cast_to<GPUParticlesCollision3D>(p_spatial) != nullptr) || (Object::cast_to<GPUParticlesAttractor3D>(p_spatial) != nullptr);
  50. }
  51. String GPUParticlesCollision3DGizmoPlugin::get_gizmo_name() const {
  52. return "GPUParticlesCollision3D";
  53. }
  54. int GPUParticlesCollision3DGizmoPlugin::get_priority() const {
  55. return -1;
  56. }
  57. String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
  58. const Node3D *cs = p_gizmo->get_node_3d();
  59. if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
  60. return "Radius";
  61. }
  62. 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)) {
  63. return helper->box_get_handle_name(p_id);
  64. }
  65. return "";
  66. }
  67. Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
  68. const Node3D *cs = p_gizmo->get_node_3d();
  69. if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
  70. return p_gizmo->get_node_3d()->call("get_radius");
  71. }
  72. 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)) {
  73. return Vector3(p_gizmo->get_node_3d()->call("get_size"));
  74. }
  75. return Variant();
  76. }
  77. void GPUParticlesCollision3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
  78. helper->initialize_handle_action(get_handle_value(p_gizmo, p_id, p_secondary), p_gizmo->get_node_3d()->get_global_transform());
  79. }
  80. void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
  81. Node3D *sn = p_gizmo->get_node_3d();
  82. Vector3 sg[2];
  83. helper->get_segment(p_camera, p_point, sg);
  84. if (Object::cast_to<GPUParticlesCollisionSphere3D>(sn) || Object::cast_to<GPUParticlesAttractorSphere3D>(sn)) {
  85. Vector3 ra, rb;
  86. Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
  87. float d = ra.x;
  88. if (Node3DEditor::get_singleton()->is_snap_enabled()) {
  89. d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
  90. }
  91. if (d < 0.001) {
  92. d = 0.001;
  93. }
  94. sn->call("set_radius", d);
  95. }
  96. 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)) {
  97. Vector3 size = sn->call("get_size");
  98. Vector3 position;
  99. helper->box_set_handle(sg, p_id, size, position);
  100. sn->call("set_size", size);
  101. sn->set_global_position(position);
  102. }
  103. }
  104. void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
  105. Node3D *sn = p_gizmo->get_node_3d();
  106. if (Object::cast_to<GPUParticlesCollisionSphere3D>(sn) || Object::cast_to<GPUParticlesAttractorSphere3D>(sn)) {
  107. if (p_cancel) {
  108. sn->call("set_radius", p_restore);
  109. return;
  110. }
  111. EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
  112. ur->create_action(TTR("Change Radius"));
  113. ur->add_do_method(sn, "set_radius", sn->call("get_radius"));
  114. ur->add_undo_method(sn, "set_radius", p_restore);
  115. ur->commit_action();
  116. }
  117. 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)) {
  118. helper->box_commit_handle("Change Box Shape Size", p_cancel, sn);
  119. }
  120. }
  121. void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
  122. Node3D *cs = p_gizmo->get_node_3d();
  123. p_gizmo->clear();
  124. Ref<Material> material;
  125. Ref<Material> material_internal;
  126. if (Object::cast_to<GPUParticlesAttractor3D>(cs)) {
  127. material = get_material("shape_material_attractor", p_gizmo);
  128. material_internal = get_material("shape_material_attractor_internal", p_gizmo);
  129. } else {
  130. material = get_material("shape_material_collision", p_gizmo);
  131. material_internal = get_material("shape_material_collision_internal", p_gizmo);
  132. }
  133. const Ref<Material> handles_material = get_material("handles");
  134. if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
  135. float radius = cs->call("get_radius");
  136. #define PUSH_QUARTER(m_from_x, m_from_y, m_to_x, m_to_y, m_y) \
  137. points_ptrw[index++] = Vector3(m_from_x, m_y, m_from_y); \
  138. points_ptrw[index++] = Vector3(m_to_x, m_y, m_to_y); \
  139. points_ptrw[index++] = Vector3(m_from_x, m_y, -m_from_y); \
  140. points_ptrw[index++] = Vector3(m_to_x, m_y, -m_to_y); \
  141. points_ptrw[index++] = Vector3(-m_from_x, m_y, m_from_y); \
  142. points_ptrw[index++] = Vector3(-m_to_x, m_y, m_to_y); \
  143. points_ptrw[index++] = Vector3(-m_from_x, m_y, -m_from_y); \
  144. points_ptrw[index++] = Vector3(-m_to_x, m_y, -m_to_y);
  145. #define PUSH_QUARTER_XY(m_from_x, m_from_y, m_to_x, m_to_y) \
  146. points_ptrw[index++] = Vector3(m_from_x, -m_from_y, 0); \
  147. points_ptrw[index++] = Vector3(m_to_x, -m_to_y, 0); \
  148. points_ptrw[index++] = Vector3(m_from_x, m_from_y, 0); \
  149. points_ptrw[index++] = Vector3(m_to_x, m_to_y, 0); \
  150. points_ptrw[index++] = Vector3(-m_from_x, -m_from_y, 0); \
  151. points_ptrw[index++] = Vector3(-m_to_x, -m_to_y, 0); \
  152. points_ptrw[index++] = Vector3(-m_from_x, m_from_y, 0); \
  153. points_ptrw[index++] = Vector3(-m_to_x, m_to_y, 0);
  154. #define PUSH_QUARTER_YZ(m_from_x, m_from_y, m_to_x, m_to_y) \
  155. points_ptrw[index++] = Vector3(0, -m_from_y, m_from_x); \
  156. points_ptrw[index++] = Vector3(0, -m_to_y, m_to_x); \
  157. points_ptrw[index++] = Vector3(0, m_from_y, m_from_x); \
  158. points_ptrw[index++] = Vector3(0, m_to_y, m_to_x); \
  159. points_ptrw[index++] = Vector3(0, -m_from_y, -m_from_x); \
  160. points_ptrw[index++] = Vector3(0, -m_to_y, -m_to_x); \
  161. points_ptrw[index++] = Vector3(0, m_from_y, -m_from_x); \
  162. points_ptrw[index++] = Vector3(0, m_to_y, -m_to_x);
  163. // Number of points in an octant. So there will be 8 * points_in_octant points in total.
  164. // This corresponds to the smoothness of the circle.
  165. const uint32_t points_in_octant = 16;
  166. const real_t octant_angle = Math::PI / 4;
  167. const real_t inc = (Math::PI / (4 * points_in_octant));
  168. const real_t radius_squared = radius * radius;
  169. real_t r = 0;
  170. Vector<Vector3> points;
  171. points.resize(3 * 8 * points_in_octant * 2);
  172. Vector3 *points_ptrw = points.ptrw();
  173. uint32_t index = 0;
  174. float previous_x = radius;
  175. float previous_y = 0.f;
  176. for (uint32_t i = 0; i < points_in_octant; ++i) {
  177. r += inc;
  178. real_t x = Math::cos((i == points_in_octant - 1) ? octant_angle : r) * radius;
  179. real_t y = Math::sqrt(radius_squared - (x * x));
  180. PUSH_QUARTER(previous_x, previous_y, x, y, 0);
  181. PUSH_QUARTER(previous_y, previous_x, y, x, 0);
  182. PUSH_QUARTER_XY(previous_x, previous_y, x, y);
  183. PUSH_QUARTER_XY(previous_y, previous_x, y, x);
  184. PUSH_QUARTER_YZ(previous_x, previous_y, x, y);
  185. PUSH_QUARTER_YZ(previous_y, previous_x, y, x);
  186. previous_x = x;
  187. previous_y = y;
  188. }
  189. p_gizmo->add_lines(points, material);
  190. p_gizmo->add_collision_segments(points);
  191. Vector<Vector3> handles;
  192. handles.push_back(Vector3(r, 0, 0));
  193. p_gizmo->add_handles(handles, handles_material);
  194. #undef PUSH_QUARTER
  195. #undef PUSH_QUARTER_XY
  196. #undef PUSH_QUARTER_YZ
  197. }
  198. 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)) {
  199. Vector<Vector3> lines;
  200. AABB aabb;
  201. aabb.size = cs->call("get_size").operator Vector3();
  202. aabb.position = aabb.size / -2;
  203. for (int i = 0; i < 12; i++) {
  204. Vector3 a, b;
  205. aabb.get_edge(i, a, b);
  206. lines.push_back(a);
  207. lines.push_back(b);
  208. }
  209. Vector<Vector3> handles = helper->box_get_handles(aabb.size);
  210. p_gizmo->add_lines(lines, material);
  211. p_gizmo->add_collision_segments(lines);
  212. p_gizmo->add_handles(handles, handles_material);
  213. GPUParticlesCollisionSDF3D *col_sdf = Object::cast_to<GPUParticlesCollisionSDF3D>(cs);
  214. if (col_sdf) {
  215. static const int subdivs[GPUParticlesCollisionSDF3D::RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
  216. int subdiv = subdivs[col_sdf->get_resolution()];
  217. float cell_size = aabb.get_longest_axis_size() / subdiv;
  218. lines.clear();
  219. for (int i = 1; i < subdiv; i++) {
  220. for (int j = 0; j < 3; j++) {
  221. if (cell_size * i > aabb.size[j]) {
  222. continue;
  223. }
  224. int j_n1 = (j + 1) % 3;
  225. int j_n2 = (j + 2) % 3;
  226. for (int k = 0; k < 4; k++) {
  227. Vector3 from = aabb.position, to = aabb.position;
  228. from[j] += cell_size * i;
  229. to[j] += cell_size * i;
  230. if (k & 1) {
  231. to[j_n1] += aabb.size[j_n1];
  232. } else {
  233. to[j_n2] += aabb.size[j_n2];
  234. }
  235. if (k & 2) {
  236. from[j_n1] += aabb.size[j_n1];
  237. from[j_n2] += aabb.size[j_n2];
  238. }
  239. lines.push_back(from);
  240. lines.push_back(to);
  241. }
  242. }
  243. }
  244. p_gizmo->add_lines(lines, material_internal);
  245. }
  246. }
  247. }