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