gpu_particles_collision_3d.cpp 34 KB

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