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