gpu_particles_collision_3d.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. /**************************************************************************/
  2. /* gpu_particles_collision_3d.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.h"
  31. #include "core/object/worker_thread_pool.h"
  32. #include "mesh_instance_3d.h"
  33. #include "scene/3d/camera_3d.h"
  34. #include "scene/main/viewport.h"
  35. void GPUParticlesCollision3D::set_cull_mask(uint32_t p_cull_mask) {
  36. cull_mask = p_cull_mask;
  37. RS::get_singleton()->particles_collision_set_cull_mask(collision, p_cull_mask);
  38. }
  39. uint32_t GPUParticlesCollision3D::get_cull_mask() const {
  40. return cull_mask;
  41. }
  42. void GPUParticlesCollision3D::_bind_methods() {
  43. ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &GPUParticlesCollision3D::set_cull_mask);
  44. ClassDB::bind_method(D_METHOD("get_cull_mask"), &GPUParticlesCollision3D::get_cull_mask);
  45. ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
  46. }
  47. GPUParticlesCollision3D::GPUParticlesCollision3D(RS::ParticlesCollisionType p_type) {
  48. collision = RS::get_singleton()->particles_collision_create();
  49. RS::get_singleton()->particles_collision_set_collision_type(collision, p_type);
  50. set_base(collision);
  51. }
  52. GPUParticlesCollision3D::~GPUParticlesCollision3D() {
  53. ERR_FAIL_NULL(RenderingServer::get_singleton());
  54. RS::get_singleton()->free(collision);
  55. }
  56. /////////////////////////////////
  57. void GPUParticlesCollisionSphere3D::_bind_methods() {
  58. ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GPUParticlesCollisionSphere3D::set_radius);
  59. ClassDB::bind_method(D_METHOD("get_radius"), &GPUParticlesCollisionSphere3D::get_radius);
  60. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_radius", "get_radius");
  61. }
  62. void GPUParticlesCollisionSphere3D::set_radius(real_t p_radius) {
  63. radius = p_radius;
  64. RS::get_singleton()->particles_collision_set_sphere_radius(_get_collision(), radius);
  65. update_gizmos();
  66. }
  67. real_t GPUParticlesCollisionSphere3D::get_radius() const {
  68. return radius;
  69. }
  70. AABB GPUParticlesCollisionSphere3D::get_aabb() const {
  71. return AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2, radius * 2, radius * 2));
  72. }
  73. GPUParticlesCollisionSphere3D::GPUParticlesCollisionSphere3D() :
  74. GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE) {
  75. }
  76. GPUParticlesCollisionSphere3D::~GPUParticlesCollisionSphere3D() {
  77. }
  78. ///////////////////////////
  79. void GPUParticlesCollisionBox3D::_bind_methods() {
  80. ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesCollisionBox3D::set_size);
  81. ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesCollisionBox3D::get_size);
  82. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
  83. }
  84. #ifndef DISABLE_DEPRECATED
  85. bool GPUParticlesCollisionBox3D::_set(const StringName &p_name, const Variant &p_value) {
  86. if (p_name == "extents") { // Compatibility with Godot 3.x.
  87. set_size((Vector3)p_value * 2);
  88. return true;
  89. }
  90. return false;
  91. }
  92. bool GPUParticlesCollisionBox3D::_get(const StringName &p_name, Variant &r_property) const {
  93. if (p_name == "extents") { // Compatibility with Godot 3.x.
  94. r_property = size / 2;
  95. return true;
  96. }
  97. return false;
  98. }
  99. #endif // DISABLE_DEPRECATED
  100. void GPUParticlesCollisionBox3D::set_size(const Vector3 &p_size) {
  101. size = p_size;
  102. RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
  103. update_gizmos();
  104. }
  105. Vector3 GPUParticlesCollisionBox3D::get_size() const {
  106. return size;
  107. }
  108. AABB GPUParticlesCollisionBox3D::get_aabb() const {
  109. return AABB(-size / 2, size);
  110. }
  111. GPUParticlesCollisionBox3D::GPUParticlesCollisionBox3D() :
  112. GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_BOX_COLLIDE) {
  113. }
  114. GPUParticlesCollisionBox3D::~GPUParticlesCollisionBox3D() {
  115. }
  116. ///////////////////////////////
  117. ///////////////////////////
  118. void GPUParticlesCollisionSDF3D::_find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes) {
  119. MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
  120. if (mi && mi->is_visible_in_tree()) {
  121. if ((mi->get_layer_mask() & bake_mask) == 0) {
  122. return;
  123. }
  124. Ref<Mesh> mesh = mi->get_mesh();
  125. if (mesh.is_valid()) {
  126. AABB aabb = mesh->get_aabb();
  127. Transform3D xf = get_global_transform().affine_inverse() * mi->get_global_transform();
  128. if (p_aabb.intersects(xf.xform(aabb))) {
  129. PlotMesh pm;
  130. pm.local_xform = xf;
  131. pm.mesh = mesh;
  132. plot_meshes.push_back(pm);
  133. }
  134. }
  135. }
  136. Node3D *s = Object::cast_to<Node3D>(p_at_node);
  137. if (s) {
  138. if (s->is_visible_in_tree()) {
  139. Array meshes = p_at_node->call("get_meshes");
  140. for (int i = 0; i < meshes.size(); i += 2) {
  141. Transform3D mxf = meshes[i];
  142. Ref<Mesh> mesh = meshes[i + 1];
  143. if (!mesh.is_valid()) {
  144. continue;
  145. }
  146. AABB aabb = mesh->get_aabb();
  147. Transform3D xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
  148. if (p_aabb.intersects(xf.xform(aabb))) {
  149. PlotMesh pm;
  150. pm.local_xform = xf;
  151. pm.mesh = mesh;
  152. plot_meshes.push_back(pm);
  153. }
  154. }
  155. }
  156. }
  157. for (int i = 0; i < p_at_node->get_child_count(); i++) {
  158. Node *child = p_at_node->get_child(i);
  159. _find_meshes(p_aabb, child, plot_meshes);
  160. }
  161. }
  162. uint32_t GPUParticlesCollisionSDF3D::_create_bvh(LocalVector<BVH> &bvh_tree, FacePos *p_faces, uint32_t p_face_count, const Face3 *p_triangles, float p_thickness) {
  163. if (p_face_count == 1) {
  164. return BVH::LEAF_BIT | p_faces[0].index;
  165. }
  166. uint32_t index = bvh_tree.size();
  167. {
  168. BVH bvh;
  169. for (uint32_t i = 0; i < p_face_count; i++) {
  170. const Face3 &f = p_triangles[p_faces[i].index];
  171. AABB aabb(f.vertex[0], Vector3());
  172. aabb.expand_to(f.vertex[1]);
  173. aabb.expand_to(f.vertex[2]);
  174. if (p_thickness > 0.0) {
  175. Vector3 normal = p_triangles[p_faces[i].index].get_plane().normal;
  176. aabb.expand_to(f.vertex[0] - normal * p_thickness);
  177. aabb.expand_to(f.vertex[1] - normal * p_thickness);
  178. aabb.expand_to(f.vertex[2] - normal * p_thickness);
  179. }
  180. if (i == 0) {
  181. bvh.bounds = aabb;
  182. } else {
  183. bvh.bounds.merge_with(aabb);
  184. }
  185. }
  186. bvh_tree.push_back(bvh);
  187. }
  188. uint32_t middle = p_face_count / 2;
  189. SortArray<FacePos, FaceSort> s;
  190. s.compare.axis = bvh_tree[index].bounds.get_longest_axis_index();
  191. s.sort(p_faces, p_face_count);
  192. uint32_t left = _create_bvh(bvh_tree, p_faces, middle, p_triangles, p_thickness);
  193. uint32_t right = _create_bvh(bvh_tree, p_faces + middle, p_face_count - middle, p_triangles, p_thickness);
  194. bvh_tree[index].children[0] = left;
  195. bvh_tree[index].children[1] = right;
  196. return index;
  197. }
  198. static _FORCE_INLINE_ real_t Vector3_dot2(const Vector3 &p_vec3) {
  199. return p_vec3.dot(p_vec3);
  200. }
  201. void GPUParticlesCollisionSDF3D::_find_closest_distance(const Vector3 &p_pos, const BVH *p_bvh, uint32_t p_bvh_cell, const Face3 *p_triangles, float p_thickness, float &r_closest_distance) {
  202. if (p_bvh_cell & BVH::LEAF_BIT) {
  203. p_bvh_cell &= BVH::LEAF_MASK; //remove bit
  204. Vector3 point = p_pos;
  205. Plane p = p_triangles[p_bvh_cell].get_plane();
  206. float d = p.distance_to(point);
  207. float inside_d = 1e20;
  208. if (d < 0 && d > -p_thickness) {
  209. //inside planes, do this in 2D
  210. Vector3 x_axis = (p_triangles[p_bvh_cell].vertex[0] - p_triangles[p_bvh_cell].vertex[1]).normalized();
  211. Vector3 y_axis = p.normal.cross(x_axis).normalized();
  212. Vector2 points[3];
  213. for (int i = 0; i < 3; i++) {
  214. points[i] = Vector2(x_axis.dot(p_triangles[p_bvh_cell].vertex[i]), y_axis.dot(p_triangles[p_bvh_cell].vertex[i]));
  215. }
  216. Vector2 p2d = Vector2(x_axis.dot(point), y_axis.dot(point));
  217. {
  218. // https://www.shadertoy.com/view/XsXSz4
  219. Vector2 e0 = points[1] - points[0];
  220. Vector2 e1 = points[2] - points[1];
  221. Vector2 e2 = points[0] - points[2];
  222. Vector2 v0 = p2d - points[0];
  223. Vector2 v1 = p2d - points[1];
  224. Vector2 v2 = p2d - points[2];
  225. Vector2 pq0 = v0 - e0 * CLAMP(v0.dot(e0) / e0.dot(e0), 0.0, 1.0);
  226. Vector2 pq1 = v1 - e1 * CLAMP(v1.dot(e1) / e1.dot(e1), 0.0, 1.0);
  227. Vector2 pq2 = v2 - e2 * CLAMP(v2.dot(e2) / e2.dot(e2), 0.0, 1.0);
  228. float s = SIGN(e0.x * e2.y - e0.y * e2.x);
  229. Vector2 d2 = Vector2(pq0.dot(pq0), s * (v0.x * e0.y - v0.y * e0.x)).min(Vector2(pq1.dot(pq1), s * (v1.x * e1.y - v1.y * e1.x))).min(Vector2(pq2.dot(pq2), s * (v2.x * e2.y - v2.y * e2.x)));
  230. inside_d = -Math::sqrt(d2.x) * SIGN(d2.y);
  231. }
  232. //make sure distance to planes is not shorter if inside
  233. if (inside_d < 0) {
  234. inside_d = MAX(inside_d, d);
  235. inside_d = MAX(inside_d, -(p_thickness + d));
  236. }
  237. r_closest_distance = MIN(r_closest_distance, inside_d);
  238. } else {
  239. if (d < 0) {
  240. point -= p.normal * p_thickness; //flatten
  241. }
  242. // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
  243. Vector3 a = p_triangles[p_bvh_cell].vertex[0];
  244. Vector3 b = p_triangles[p_bvh_cell].vertex[1];
  245. Vector3 c = p_triangles[p_bvh_cell].vertex[2];
  246. Vector3 ba = b - a;
  247. Vector3 pa = point - a;
  248. Vector3 cb = c - b;
  249. Vector3 pb = point - b;
  250. Vector3 ac = a - c;
  251. Vector3 pc = point - c;
  252. Vector3 nor = ba.cross(ac);
  253. inside_d = Math::sqrt(
  254. (SIGN(ba.cross(nor).dot(pa)) + SIGN(cb.cross(nor).dot(pb)) + SIGN(ac.cross(nor).dot(pc)) < 2.0)
  255. ? MIN(MIN(
  256. Vector3_dot2(ba * CLAMP(ba.dot(pa) / Vector3_dot2(ba), 0.0, 1.0) - pa),
  257. Vector3_dot2(cb * CLAMP(cb.dot(pb) / Vector3_dot2(cb), 0.0, 1.0) - pb)),
  258. Vector3_dot2(ac * CLAMP(ac.dot(pc) / Vector3_dot2(ac), 0.0, 1.0) - pc))
  259. : nor.dot(pa) * nor.dot(pa) / Vector3_dot2(nor));
  260. r_closest_distance = MIN(r_closest_distance, inside_d);
  261. }
  262. } else {
  263. bool pass = true;
  264. if (!p_bvh[p_bvh_cell].bounds.has_point(p_pos)) {
  265. //outside, find closest point
  266. Vector3 he = p_bvh[p_bvh_cell].bounds.size * 0.5;
  267. Vector3 center = p_bvh[p_bvh_cell].bounds.position + he;
  268. Vector3 rel = (p_pos - center).abs();
  269. Vector3 closest = rel.min(he);
  270. float d = rel.distance_to(closest);
  271. if (d >= r_closest_distance) {
  272. pass = false; //already closer than this aabb, discard
  273. }
  274. }
  275. if (pass) {
  276. _find_closest_distance(p_pos, p_bvh, p_bvh[p_bvh_cell].children[0], p_triangles, p_thickness, r_closest_distance);
  277. _find_closest_distance(p_pos, p_bvh, p_bvh[p_bvh_cell].children[1], p_triangles, p_thickness, r_closest_distance);
  278. }
  279. }
  280. }
  281. void GPUParticlesCollisionSDF3D::_compute_sdf_z(uint32_t p_z, ComputeSDFParams *params) {
  282. int32_t z_ofs = p_z * params->size.y * params->size.x;
  283. for (int32_t y = 0; y < params->size.y; y++) {
  284. int32_t y_ofs = z_ofs + y * params->size.x;
  285. for (int32_t x = 0; x < params->size.x; x++) {
  286. int32_t x_ofs = y_ofs + x;
  287. float &cell = params->cells[x_ofs];
  288. Vector3 pos = params->cell_offset + Vector3(x, y, p_z) * params->cell_size;
  289. cell = 1e20;
  290. _find_closest_distance(pos, params->bvh, 0, params->triangles, params->thickness, cell);
  291. }
  292. }
  293. }
  294. void GPUParticlesCollisionSDF3D::_compute_sdf(ComputeSDFParams *params) {
  295. WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GPUParticlesCollisionSDF3D::_compute_sdf_z, params, params->size.z);
  296. while (!WorkerThreadPool::get_singleton()->is_group_task_completed(group_task)) {
  297. OS::get_singleton()->delay_usec(10000);
  298. if (bake_step_function) {
  299. bake_step_function(WorkerThreadPool::get_singleton()->get_group_processed_element_count(group_task) * 100 / params->size.z, "Baking SDF");
  300. }
  301. }
  302. WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
  303. }
  304. Vector3i GPUParticlesCollisionSDF3D::get_estimated_cell_size() const {
  305. static const int subdivs[RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
  306. int subdiv = subdivs[get_resolution()];
  307. AABB aabb(-size / 2, size);
  308. float cell_size = aabb.get_longest_axis_size() / float(subdiv);
  309. Vector3i sdf_size = Vector3i(aabb.size / cell_size);
  310. sdf_size = sdf_size.maxi(1);
  311. return sdf_size;
  312. }
  313. Ref<Image> GPUParticlesCollisionSDF3D::bake() {
  314. static const int subdivs[RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
  315. int subdiv = subdivs[get_resolution()];
  316. AABB aabb(-size / 2, size);
  317. float cell_size = aabb.get_longest_axis_size() / float(subdiv);
  318. Vector3i sdf_size = Vector3i(aabb.size / cell_size);
  319. sdf_size = sdf_size.maxi(1);
  320. if (bake_begin_function) {
  321. bake_begin_function(100);
  322. }
  323. aabb.size = Vector3(sdf_size) * cell_size;
  324. List<PlotMesh> plot_meshes;
  325. _find_meshes(aabb, get_parent(), plot_meshes);
  326. LocalVector<Face3> faces;
  327. if (bake_step_function) {
  328. bake_step_function(0, "Finding Meshes");
  329. }
  330. for (const PlotMesh &pm : plot_meshes) {
  331. for (int i = 0; i < pm.mesh->get_surface_count(); i++) {
  332. if (pm.mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
  333. continue; //only triangles
  334. }
  335. Array a = pm.mesh->surface_get_arrays(i);
  336. Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
  337. const Vector3 *vr = vertices.ptr();
  338. Vector<int> index = a[Mesh::ARRAY_INDEX];
  339. if (index.size()) {
  340. int facecount = index.size() / 3;
  341. const int *ir = index.ptr();
  342. for (int j = 0; j < facecount; j++) {
  343. Face3 face;
  344. for (int k = 0; k < 3; k++) {
  345. face.vertex[k] = pm.local_xform.xform(vr[ir[j * 3 + k]]);
  346. }
  347. //test against original bounds
  348. if (!Geometry3D::triangle_box_overlap(aabb.get_center(), aabb.size * 0.5, face.vertex)) {
  349. continue;
  350. }
  351. faces.push_back(face);
  352. }
  353. } else {
  354. int facecount = vertices.size() / 3;
  355. for (int j = 0; j < facecount; j++) {
  356. Face3 face;
  357. for (int k = 0; k < 3; k++) {
  358. face.vertex[k] = pm.local_xform.xform(vr[j * 3 + k]);
  359. }
  360. //test against original bounds
  361. if (!Geometry3D::triangle_box_overlap(aabb.get_center(), aabb.size * 0.5, face.vertex)) {
  362. continue;
  363. }
  364. faces.push_back(face);
  365. }
  366. }
  367. }
  368. }
  369. //compute bvh
  370. if (faces.size() <= 1) {
  371. ERR_PRINT("No faces detected during GPUParticlesCollisionSDF3D bake. Check whether there are visible meshes matching the bake mask within its extents.");
  372. if (bake_end_function) {
  373. bake_end_function();
  374. }
  375. return Ref<Image>();
  376. }
  377. LocalVector<FacePos> face_pos;
  378. face_pos.resize(faces.size());
  379. float th = cell_size * thickness;
  380. for (uint32_t i = 0; i < faces.size(); i++) {
  381. face_pos[i].index = i;
  382. face_pos[i].center = (faces[i].vertex[0] + faces[i].vertex[1] + faces[i].vertex[2]) / 2;
  383. if (th > 0.0) {
  384. face_pos[i].center -= faces[i].get_plane().normal * th * 0.5;
  385. }
  386. }
  387. if (bake_step_function) {
  388. bake_step_function(0, "Creating BVH");
  389. }
  390. LocalVector<BVH> bvh;
  391. _create_bvh(bvh, face_pos.ptr(), face_pos.size(), faces.ptr(), th);
  392. Vector<uint8_t> cells_data;
  393. cells_data.resize(sdf_size.z * sdf_size.y * sdf_size.x * (int)sizeof(float));
  394. if (bake_step_function) {
  395. bake_step_function(0, "Baking SDF");
  396. }
  397. ComputeSDFParams params;
  398. params.cells = (float *)cells_data.ptrw();
  399. params.size = sdf_size;
  400. params.cell_size = cell_size;
  401. params.cell_offset = aabb.position + Vector3(cell_size * 0.5, cell_size * 0.5, cell_size * 0.5);
  402. params.bvh = bvh.ptr();
  403. params.triangles = faces.ptr();
  404. params.thickness = th;
  405. _compute_sdf(&params);
  406. Ref<Image> ret = Image::create_from_data(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, cells_data);
  407. ret->convert(Image::FORMAT_RH); //convert to half, save space
  408. ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function
  409. if (bake_end_function) {
  410. bake_end_function();
  411. }
  412. return ret;
  413. }
  414. PackedStringArray GPUParticlesCollisionSDF3D::get_configuration_warnings() const {
  415. PackedStringArray warnings = GPUParticlesCollision3D::get_configuration_warnings();
  416. if (bake_mask == 0) {
  417. warnings.push_back(RTR("The Bake Mask has no bits enabled, which means baking will not produce any collision for this GPUParticlesCollisionSDF3D.\nTo resolve this, enable at least one bit in the Bake Mask property."));
  418. }
  419. return warnings;
  420. }
  421. void GPUParticlesCollisionSDF3D::_bind_methods() {
  422. ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesCollisionSDF3D::set_size);
  423. ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesCollisionSDF3D::get_size);
  424. ClassDB::bind_method(D_METHOD("set_resolution", "resolution"), &GPUParticlesCollisionSDF3D::set_resolution);
  425. ClassDB::bind_method(D_METHOD("get_resolution"), &GPUParticlesCollisionSDF3D::get_resolution);
  426. ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticlesCollisionSDF3D::set_texture);
  427. ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticlesCollisionSDF3D::get_texture);
  428. ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &GPUParticlesCollisionSDF3D::set_thickness);
  429. ClassDB::bind_method(D_METHOD("get_thickness"), &GPUParticlesCollisionSDF3D::get_thickness);
  430. ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &GPUParticlesCollisionSDF3D::set_bake_mask);
  431. ClassDB::bind_method(D_METHOD("get_bake_mask"), &GPUParticlesCollisionSDF3D::get_bake_mask);
  432. ClassDB::bind_method(D_METHOD("set_bake_mask_value", "layer_number", "value"), &GPUParticlesCollisionSDF3D::set_bake_mask_value);
  433. ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &GPUParticlesCollisionSDF3D::get_bake_mask_value);
  434. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
  435. ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512"), "set_resolution", "get_resolution");
  436. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,suffix:m"), "set_thickness", "get_thickness");
  437. ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
  438. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
  439. BIND_ENUM_CONSTANT(RESOLUTION_16);
  440. BIND_ENUM_CONSTANT(RESOLUTION_32);
  441. BIND_ENUM_CONSTANT(RESOLUTION_64);
  442. BIND_ENUM_CONSTANT(RESOLUTION_128);
  443. BIND_ENUM_CONSTANT(RESOLUTION_256);
  444. BIND_ENUM_CONSTANT(RESOLUTION_512);
  445. BIND_ENUM_CONSTANT(RESOLUTION_MAX);
  446. }
  447. #ifndef DISABLE_DEPRECATED
  448. bool GPUParticlesCollisionSDF3D::_set(const StringName &p_name, const Variant &p_value) {
  449. if (p_name == "extents") { // Compatibility with Godot 3.x.
  450. set_size((Vector3)p_value * 2);
  451. return true;
  452. }
  453. return false;
  454. }
  455. bool GPUParticlesCollisionSDF3D::_get(const StringName &p_name, Variant &r_property) const {
  456. if (p_name == "extents") { // Compatibility with Godot 3.x.
  457. r_property = size / 2;
  458. return true;
  459. }
  460. return false;
  461. }
  462. #endif // DISABLE_DEPRECATED
  463. void GPUParticlesCollisionSDF3D::set_thickness(float p_thickness) {
  464. thickness = p_thickness;
  465. }
  466. float GPUParticlesCollisionSDF3D::get_thickness() const {
  467. return thickness;
  468. }
  469. void GPUParticlesCollisionSDF3D::set_size(const Vector3 &p_size) {
  470. size = p_size;
  471. RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
  472. update_gizmos();
  473. }
  474. Vector3 GPUParticlesCollisionSDF3D::get_size() const {
  475. return size;
  476. }
  477. void GPUParticlesCollisionSDF3D::set_resolution(Resolution p_resolution) {
  478. resolution = p_resolution;
  479. update_gizmos();
  480. }
  481. GPUParticlesCollisionSDF3D::Resolution GPUParticlesCollisionSDF3D::get_resolution() const {
  482. return resolution;
  483. }
  484. void GPUParticlesCollisionSDF3D::set_bake_mask(uint32_t p_mask) {
  485. bake_mask = p_mask;
  486. update_configuration_warnings();
  487. }
  488. uint32_t GPUParticlesCollisionSDF3D::get_bake_mask() const {
  489. return bake_mask;
  490. }
  491. void GPUParticlesCollisionSDF3D::set_bake_mask_value(int p_layer_number, bool p_value) {
  492. ERR_FAIL_COND_MSG(p_layer_number < 1 || p_layer_number > 20, vformat("The render layer number (%d) must be between 1 and 20 (inclusive).", p_layer_number));
  493. uint32_t mask = get_bake_mask();
  494. if (p_value) {
  495. mask |= 1 << (p_layer_number - 1);
  496. } else {
  497. mask &= ~(1 << (p_layer_number - 1));
  498. }
  499. set_bake_mask(mask);
  500. }
  501. bool GPUParticlesCollisionSDF3D::get_bake_mask_value(int p_layer_number) const {
  502. ERR_FAIL_COND_V_MSG(p_layer_number < 1 || p_layer_number > 20, false, vformat("The render layer number (%d) must be between 1 and 20 (inclusive).", p_layer_number));
  503. return bake_mask & (1 << (p_layer_number - 1));
  504. }
  505. void GPUParticlesCollisionSDF3D::set_texture(const Ref<Texture3D> &p_texture) {
  506. texture = p_texture;
  507. RID tex = texture.is_valid() ? texture->get_rid() : RID();
  508. RS::get_singleton()->particles_collision_set_field_texture(_get_collision(), tex);
  509. }
  510. Ref<Texture3D> GPUParticlesCollisionSDF3D::get_texture() const {
  511. return texture;
  512. }
  513. AABB GPUParticlesCollisionSDF3D::get_aabb() const {
  514. return AABB(-size / 2, size);
  515. }
  516. GPUParticlesCollisionSDF3D::BakeBeginFunc GPUParticlesCollisionSDF3D::bake_begin_function = nullptr;
  517. GPUParticlesCollisionSDF3D::BakeStepFunc GPUParticlesCollisionSDF3D::bake_step_function = nullptr;
  518. GPUParticlesCollisionSDF3D::BakeEndFunc GPUParticlesCollisionSDF3D::bake_end_function = nullptr;
  519. GPUParticlesCollisionSDF3D::GPUParticlesCollisionSDF3D() :
  520. GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_SDF_COLLIDE) {
  521. }
  522. GPUParticlesCollisionSDF3D::~GPUParticlesCollisionSDF3D() {
  523. }
  524. ////////////////////////////
  525. ////////////////////////////
  526. void GPUParticlesCollisionHeightField3D::_notification(int p_what) {
  527. switch (p_what) {
  528. case NOTIFICATION_INTERNAL_PROCESS: {
  529. if (update_mode == UPDATE_MODE_ALWAYS) {
  530. RS::get_singleton()->particles_collision_height_field_update(_get_collision());
  531. }
  532. if (follow_camera_mode && get_viewport()) {
  533. Camera3D *cam = get_viewport()->get_camera_3d();
  534. if (cam) {
  535. Transform3D xform = get_global_transform();
  536. Vector3 x_axis = xform.basis.get_column(Vector3::AXIS_X).normalized();
  537. Vector3 z_axis = xform.basis.get_column(Vector3::AXIS_Z).normalized();
  538. float x_len = xform.basis.get_scale().x;
  539. float z_len = xform.basis.get_scale().z;
  540. Vector3 cam_pos = cam->get_global_transform().origin;
  541. Transform3D new_xform = xform;
  542. while (x_axis.dot(cam_pos - new_xform.origin) > x_len) {
  543. new_xform.origin += x_axis * x_len;
  544. }
  545. while (x_axis.dot(cam_pos - new_xform.origin) < -x_len) {
  546. new_xform.origin -= x_axis * x_len;
  547. }
  548. while (z_axis.dot(cam_pos - new_xform.origin) > z_len) {
  549. new_xform.origin += z_axis * z_len;
  550. }
  551. while (z_axis.dot(cam_pos - new_xform.origin) < -z_len) {
  552. new_xform.origin -= z_axis * z_len;
  553. }
  554. if (new_xform != xform) {
  555. set_global_transform(new_xform);
  556. RS::get_singleton()->particles_collision_height_field_update(_get_collision());
  557. }
  558. }
  559. }
  560. } break;
  561. case NOTIFICATION_TRANSFORM_CHANGED: {
  562. RS::get_singleton()->particles_collision_height_field_update(_get_collision());
  563. } break;
  564. }
  565. }
  566. void GPUParticlesCollisionHeightField3D::_bind_methods() {
  567. ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesCollisionHeightField3D::set_size);
  568. ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesCollisionHeightField3D::get_size);
  569. ClassDB::bind_method(D_METHOD("set_resolution", "resolution"), &GPUParticlesCollisionHeightField3D::set_resolution);
  570. ClassDB::bind_method(D_METHOD("get_resolution"), &GPUParticlesCollisionHeightField3D::get_resolution);
  571. ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &GPUParticlesCollisionHeightField3D::set_update_mode);
  572. ClassDB::bind_method(D_METHOD("get_update_mode"), &GPUParticlesCollisionHeightField3D::get_update_mode);
  573. ClassDB::bind_method(D_METHOD("set_follow_camera_enabled", "enabled"), &GPUParticlesCollisionHeightField3D::set_follow_camera_enabled);
  574. ClassDB::bind_method(D_METHOD("is_follow_camera_enabled"), &GPUParticlesCollisionHeightField3D::is_follow_camera_enabled);
  575. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
  576. ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "256 (Fastest),512 (Fast),1024 (Average),2048 (Slow),4096 (Slower),8192 (Slowest)"), "set_resolution", "get_resolution");
  577. ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "When Moved (Fast),Always (Slow)"), "set_update_mode", "get_update_mode");
  578. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_camera_enabled"), "set_follow_camera_enabled", "is_follow_camera_enabled");
  579. BIND_ENUM_CONSTANT(RESOLUTION_256);
  580. BIND_ENUM_CONSTANT(RESOLUTION_512);
  581. BIND_ENUM_CONSTANT(RESOLUTION_1024);
  582. BIND_ENUM_CONSTANT(RESOLUTION_2048);
  583. BIND_ENUM_CONSTANT(RESOLUTION_4096);
  584. BIND_ENUM_CONSTANT(RESOLUTION_8192);
  585. BIND_ENUM_CONSTANT(RESOLUTION_MAX);
  586. BIND_ENUM_CONSTANT(UPDATE_MODE_WHEN_MOVED);
  587. BIND_ENUM_CONSTANT(UPDATE_MODE_ALWAYS);
  588. }
  589. #ifndef DISABLE_DEPRECATED
  590. bool GPUParticlesCollisionHeightField3D::_set(const StringName &p_name, const Variant &p_value) {
  591. if (p_name == "extents") { // Compatibility with Godot 3.x.
  592. set_size((Vector3)p_value * 2);
  593. return true;
  594. }
  595. return false;
  596. }
  597. bool GPUParticlesCollisionHeightField3D::_get(const StringName &p_name, Variant &r_property) const {
  598. if (p_name == "extents") { // Compatibility with Godot 3.x.
  599. r_property = size / 2;
  600. return true;
  601. }
  602. return false;
  603. }
  604. #endif // DISABLE_DEPRECATED
  605. void GPUParticlesCollisionHeightField3D::set_size(const Vector3 &p_size) {
  606. size = p_size;
  607. RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
  608. update_gizmos();
  609. RS::get_singleton()->particles_collision_height_field_update(_get_collision());
  610. }
  611. Vector3 GPUParticlesCollisionHeightField3D::get_size() const {
  612. return size;
  613. }
  614. void GPUParticlesCollisionHeightField3D::set_resolution(Resolution p_resolution) {
  615. resolution = p_resolution;
  616. RS::get_singleton()->particles_collision_set_height_field_resolution(_get_collision(), RS::ParticlesCollisionHeightfieldResolution(resolution));
  617. update_gizmos();
  618. RS::get_singleton()->particles_collision_height_field_update(_get_collision());
  619. }
  620. GPUParticlesCollisionHeightField3D::Resolution GPUParticlesCollisionHeightField3D::get_resolution() const {
  621. return resolution;
  622. }
  623. void GPUParticlesCollisionHeightField3D::set_update_mode(UpdateMode p_update_mode) {
  624. update_mode = p_update_mode;
  625. set_process_internal(follow_camera_mode || update_mode == UPDATE_MODE_ALWAYS);
  626. }
  627. GPUParticlesCollisionHeightField3D::UpdateMode GPUParticlesCollisionHeightField3D::get_update_mode() const {
  628. return update_mode;
  629. }
  630. void GPUParticlesCollisionHeightField3D::set_follow_camera_enabled(bool p_enabled) {
  631. follow_camera_mode = p_enabled;
  632. set_process_internal(follow_camera_mode || update_mode == UPDATE_MODE_ALWAYS);
  633. }
  634. bool GPUParticlesCollisionHeightField3D::is_follow_camera_enabled() const {
  635. return follow_camera_mode;
  636. }
  637. AABB GPUParticlesCollisionHeightField3D::get_aabb() const {
  638. return AABB(-size / 2, size);
  639. }
  640. GPUParticlesCollisionHeightField3D::GPUParticlesCollisionHeightField3D() :
  641. GPUParticlesCollision3D(RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE) {
  642. }
  643. GPUParticlesCollisionHeightField3D::~GPUParticlesCollisionHeightField3D() {
  644. }
  645. ////////////////////////////
  646. ////////////////////////////
  647. void GPUParticlesAttractor3D::set_cull_mask(uint32_t p_cull_mask) {
  648. cull_mask = p_cull_mask;
  649. RS::get_singleton()->particles_collision_set_cull_mask(collision, p_cull_mask);
  650. }
  651. uint32_t GPUParticlesAttractor3D::get_cull_mask() const {
  652. return cull_mask;
  653. }
  654. void GPUParticlesAttractor3D::set_strength(real_t p_strength) {
  655. strength = p_strength;
  656. RS::get_singleton()->particles_collision_set_attractor_strength(collision, p_strength);
  657. }
  658. real_t GPUParticlesAttractor3D::get_strength() const {
  659. return strength;
  660. }
  661. void GPUParticlesAttractor3D::set_attenuation(real_t p_attenuation) {
  662. attenuation = p_attenuation;
  663. RS::get_singleton()->particles_collision_set_attractor_attenuation(collision, p_attenuation);
  664. }
  665. real_t GPUParticlesAttractor3D::get_attenuation() const {
  666. return attenuation;
  667. }
  668. void GPUParticlesAttractor3D::set_directionality(real_t p_directionality) {
  669. directionality = p_directionality;
  670. RS::get_singleton()->particles_collision_set_attractor_directionality(collision, p_directionality);
  671. update_gizmos();
  672. }
  673. real_t GPUParticlesAttractor3D::get_directionality() const {
  674. return directionality;
  675. }
  676. void GPUParticlesAttractor3D::_bind_methods() {
  677. ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &GPUParticlesAttractor3D::set_cull_mask);
  678. ClassDB::bind_method(D_METHOD("get_cull_mask"), &GPUParticlesAttractor3D::get_cull_mask);
  679. ClassDB::bind_method(D_METHOD("set_strength", "strength"), &GPUParticlesAttractor3D::set_strength);
  680. ClassDB::bind_method(D_METHOD("get_strength"), &GPUParticlesAttractor3D::get_strength);
  681. ClassDB::bind_method(D_METHOD("set_attenuation", "attenuation"), &GPUParticlesAttractor3D::set_attenuation);
  682. ClassDB::bind_method(D_METHOD("get_attenuation"), &GPUParticlesAttractor3D::get_attenuation);
  683. ClassDB::bind_method(D_METHOD("set_directionality", "amount"), &GPUParticlesAttractor3D::set_directionality);
  684. ClassDB::bind_method(D_METHOD("get_directionality"), &GPUParticlesAttractor3D::get_directionality);
  685. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_less"), "set_strength", "get_strength");
  686. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "0,8,0.01"), "set_attenuation", "get_attenuation");
  687. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "directionality", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_directionality", "get_directionality");
  688. ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
  689. }
  690. GPUParticlesAttractor3D::GPUParticlesAttractor3D(RS::ParticlesCollisionType p_type) {
  691. collision = RS::get_singleton()->particles_collision_create();
  692. RS::get_singleton()->particles_collision_set_collision_type(collision, p_type);
  693. set_base(collision);
  694. }
  695. GPUParticlesAttractor3D::~GPUParticlesAttractor3D() {
  696. ERR_FAIL_NULL(RenderingServer::get_singleton());
  697. RS::get_singleton()->free(collision);
  698. }
  699. /////////////////////////////////
  700. void GPUParticlesAttractorSphere3D::_bind_methods() {
  701. ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GPUParticlesAttractorSphere3D::set_radius);
  702. ClassDB::bind_method(D_METHOD("get_radius"), &GPUParticlesAttractorSphere3D::get_radius);
  703. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_radius", "get_radius");
  704. }
  705. void GPUParticlesAttractorSphere3D::set_radius(real_t p_radius) {
  706. radius = p_radius;
  707. RS::get_singleton()->particles_collision_set_sphere_radius(_get_collision(), radius);
  708. update_gizmos();
  709. }
  710. real_t GPUParticlesAttractorSphere3D::get_radius() const {
  711. return radius;
  712. }
  713. AABB GPUParticlesAttractorSphere3D::get_aabb() const {
  714. return AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2, radius * 2, radius * 2));
  715. }
  716. GPUParticlesAttractorSphere3D::GPUParticlesAttractorSphere3D() :
  717. GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT) {
  718. }
  719. GPUParticlesAttractorSphere3D::~GPUParticlesAttractorSphere3D() {
  720. }
  721. ///////////////////////////
  722. void GPUParticlesAttractorBox3D::_bind_methods() {
  723. ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesAttractorBox3D::set_size);
  724. ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesAttractorBox3D::get_size);
  725. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
  726. }
  727. #ifndef DISABLE_DEPRECATED
  728. bool GPUParticlesAttractorBox3D::_set(const StringName &p_name, const Variant &p_value) {
  729. if (p_name == "extents") { // Compatibility with Godot 3.x.
  730. set_size((Vector3)p_value * 2);
  731. return true;
  732. }
  733. return false;
  734. }
  735. bool GPUParticlesAttractorBox3D::_get(const StringName &p_name, Variant &r_property) const {
  736. if (p_name == "extents") { // Compatibility with Godot 3.x.
  737. r_property = size / 2;
  738. return true;
  739. }
  740. return false;
  741. }
  742. #endif // DISABLE_DEPRECATED
  743. void GPUParticlesAttractorBox3D::set_size(const Vector3 &p_size) {
  744. size = p_size;
  745. RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
  746. update_gizmos();
  747. }
  748. Vector3 GPUParticlesAttractorBox3D::get_size() const {
  749. return size;
  750. }
  751. AABB GPUParticlesAttractorBox3D::get_aabb() const {
  752. return AABB(-size / 2, size);
  753. }
  754. GPUParticlesAttractorBox3D::GPUParticlesAttractorBox3D() :
  755. GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_BOX_ATTRACT) {
  756. }
  757. GPUParticlesAttractorBox3D::~GPUParticlesAttractorBox3D() {
  758. }
  759. ///////////////////////////
  760. void GPUParticlesAttractorVectorField3D::_bind_methods() {
  761. ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesAttractorVectorField3D::set_size);
  762. ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesAttractorVectorField3D::get_size);
  763. ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticlesAttractorVectorField3D::set_texture);
  764. ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticlesAttractorVectorField3D::get_texture);
  765. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
  766. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
  767. }
  768. #ifndef DISABLE_DEPRECATED
  769. bool GPUParticlesAttractorVectorField3D::_set(const StringName &p_name, const Variant &p_value) {
  770. if (p_name == "extents") { // Compatibility with Godot 3.x.
  771. set_size((Vector3)p_value * 2);
  772. return true;
  773. }
  774. return false;
  775. }
  776. bool GPUParticlesAttractorVectorField3D::_get(const StringName &p_name, Variant &r_property) const {
  777. if (p_name == "extents") { // Compatibility with Godot 3.x.
  778. r_property = size / 2;
  779. return true;
  780. }
  781. return false;
  782. }
  783. #endif // DISABLE_DEPRECATED
  784. void GPUParticlesAttractorVectorField3D::set_size(const Vector3 &p_size) {
  785. size = p_size;
  786. RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
  787. update_gizmos();
  788. }
  789. Vector3 GPUParticlesAttractorVectorField3D::get_size() const {
  790. return size;
  791. }
  792. void GPUParticlesAttractorVectorField3D::set_texture(const Ref<Texture3D> &p_texture) {
  793. texture = p_texture;
  794. RID tex = texture.is_valid() ? texture->get_rid() : RID();
  795. RS::get_singleton()->particles_collision_set_field_texture(_get_collision(), tex);
  796. }
  797. Ref<Texture3D> GPUParticlesAttractorVectorField3D::get_texture() const {
  798. return texture;
  799. }
  800. AABB GPUParticlesAttractorVectorField3D::get_aabb() const {
  801. return AABB(-size / 2, size);
  802. }
  803. GPUParticlesAttractorVectorField3D::GPUParticlesAttractorVectorField3D() :
  804. GPUParticlesAttractor3D(RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT) {
  805. }
  806. GPUParticlesAttractorVectorField3D::~GPUParticlesAttractorVectorField3D() {
  807. }