Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/3d/cpu_particles_3d.cpp
20849 views
1
/**************************************************************************/
2
/* cpu_particles_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 "cpu_particles_3d.h"
32
#include "cpu_particles_3d.compat.inc"
33
34
#include "core/math/random_number_generator.h"
35
#include "scene/3d/camera_3d.h"
36
#include "scene/3d/gpu_particles_3d.h"
37
#include "scene/main/viewport.h"
38
#include "scene/resources/curve_texture.h"
39
#include "scene/resources/gradient_texture.h"
40
#include "scene/resources/mesh.h"
41
#include "scene/resources/particle_process_material.h"
42
43
AABB CPUParticles3D::get_aabb() const {
44
return AABB();
45
}
46
47
void CPUParticles3D::set_emitting(bool p_emitting) {
48
if (emitting == p_emitting) {
49
return;
50
}
51
52
if (p_emitting && !use_fixed_seed && one_shot) {
53
set_seed(Math::rand());
54
}
55
56
emitting = p_emitting;
57
if (emitting) {
58
_set_emitting();
59
}
60
}
61
62
void CPUParticles3D::_set_emitting() {
63
active = true;
64
set_process_internal(true);
65
// first update before rendering to avoid one frame delay after emitting starts
66
if (time == 0) {
67
_update_internal();
68
}
69
}
70
71
void CPUParticles3D::set_amount(int p_amount) {
72
ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0.");
73
74
particles.resize(p_amount);
75
{
76
Particle *w = particles.ptrw();
77
78
for (int i = 0; i < p_amount; i++) {
79
w[i].active = false;
80
w[i].custom[3] = 1.0; // Make sure w component isn't garbage data and doesn't break shaders with CUSTOM.y/Custom.w
81
}
82
}
83
84
particle_data.resize((12 + 4 + 4) * p_amount);
85
RS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
86
RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_3D, true, true);
87
88
particle_order.resize(p_amount);
89
}
90
91
void CPUParticles3D::set_lifetime(double p_lifetime) {
92
ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
93
lifetime = p_lifetime;
94
}
95
96
void CPUParticles3D::set_one_shot(bool p_one_shot) {
97
one_shot = p_one_shot;
98
}
99
100
void CPUParticles3D::set_pre_process_time(double p_time) {
101
pre_process_time = p_time;
102
}
103
104
void CPUParticles3D::set_explosiveness_ratio(real_t p_ratio) {
105
explosiveness_ratio = p_ratio;
106
}
107
108
void CPUParticles3D::set_randomness_ratio(real_t p_ratio) {
109
randomness_ratio = p_ratio;
110
}
111
112
void CPUParticles3D::set_visibility_aabb(const AABB &p_aabb) {
113
RS::get_singleton()->multimesh_set_custom_aabb(multimesh, p_aabb);
114
visibility_aabb = p_aabb;
115
update_gizmos();
116
}
117
118
void CPUParticles3D::set_lifetime_randomness(double p_random) {
119
lifetime_randomness = p_random;
120
}
121
122
void CPUParticles3D::set_use_local_coordinates(bool p_enable) {
123
local_coords = p_enable;
124
}
125
126
void CPUParticles3D::set_speed_scale(double p_scale) {
127
speed_scale = p_scale;
128
}
129
130
bool CPUParticles3D::is_emitting() const {
131
return emitting;
132
}
133
134
int CPUParticles3D::get_amount() const {
135
return particles.size();
136
}
137
138
double CPUParticles3D::get_lifetime() const {
139
return lifetime;
140
}
141
142
bool CPUParticles3D::get_one_shot() const {
143
return one_shot;
144
}
145
146
double CPUParticles3D::get_pre_process_time() const {
147
return pre_process_time;
148
}
149
150
real_t CPUParticles3D::get_explosiveness_ratio() const {
151
return explosiveness_ratio;
152
}
153
154
real_t CPUParticles3D::get_randomness_ratio() const {
155
return randomness_ratio;
156
}
157
158
AABB CPUParticles3D::get_visibility_aabb() const {
159
return visibility_aabb;
160
}
161
162
double CPUParticles3D::get_lifetime_randomness() const {
163
return lifetime_randomness;
164
}
165
166
bool CPUParticles3D::get_use_local_coordinates() const {
167
return local_coords;
168
}
169
170
double CPUParticles3D::get_speed_scale() const {
171
return speed_scale;
172
}
173
174
void CPUParticles3D::set_draw_order(DrawOrder p_order) {
175
ERR_FAIL_INDEX(p_order, DRAW_ORDER_MAX);
176
draw_order = p_order;
177
}
178
179
CPUParticles3D::DrawOrder CPUParticles3D::get_draw_order() const {
180
return draw_order;
181
}
182
183
void CPUParticles3D::set_mesh(const Ref<Mesh> &p_mesh) {
184
mesh = p_mesh;
185
if (mesh.is_valid()) {
186
RS::get_singleton()->multimesh_set_mesh(multimesh, mesh->get_rid());
187
} else {
188
RS::get_singleton()->multimesh_set_mesh(multimesh, RID());
189
}
190
191
update_configuration_warnings();
192
}
193
194
Ref<Mesh> CPUParticles3D::get_mesh() const {
195
return mesh;
196
}
197
198
void CPUParticles3D::set_fixed_fps(int p_count) {
199
fixed_fps = p_count;
200
}
201
202
int CPUParticles3D::get_fixed_fps() const {
203
return fixed_fps;
204
}
205
206
void CPUParticles3D::set_fractional_delta(bool p_enable) {
207
fractional_delta = p_enable;
208
}
209
210
bool CPUParticles3D::get_fractional_delta() const {
211
return fractional_delta;
212
}
213
214
PackedStringArray CPUParticles3D::get_configuration_warnings() const {
215
PackedStringArray warnings = GeometryInstance3D::get_configuration_warnings();
216
217
bool mesh_found = false;
218
bool anim_material_found = false;
219
220
if (get_mesh().is_valid()) {
221
mesh_found = true;
222
for (int j = 0; j < get_mesh()->get_surface_count(); j++) {
223
anim_material_found = Object::cast_to<ShaderMaterial>(get_mesh()->surface_get_material(j).ptr()) != nullptr;
224
StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_mesh()->surface_get_material(j).ptr());
225
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
226
}
227
}
228
229
anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != nullptr;
230
StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr());
231
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
232
233
if (!mesh_found) {
234
warnings.push_back(RTR("Nothing is visible because no mesh has been assigned."));
235
}
236
237
if (!anim_material_found && (get_param_max(PARAM_ANIM_SPEED) != 0.0 || get_param_max(PARAM_ANIM_OFFSET) != 0.0 || get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) {
238
warnings.push_back(RTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
239
}
240
241
return warnings;
242
}
243
244
void CPUParticles3D::restart(bool p_keep_seed) {
245
time = 0;
246
frame_remainder = 0;
247
cycle = 0;
248
emitting = false;
249
250
{
251
int pc = particles.size();
252
Particle *w = particles.ptrw();
253
254
for (int i = 0; i < pc; i++) {
255
w[i].active = false;
256
}
257
}
258
if (!p_keep_seed && !use_fixed_seed) {
259
seed = Math::rand();
260
}
261
262
emitting = true;
263
_set_emitting();
264
}
265
266
void CPUParticles3D::set_direction(Vector3 p_direction) {
267
direction = p_direction;
268
}
269
270
Vector3 CPUParticles3D::get_direction() const {
271
return direction;
272
}
273
274
void CPUParticles3D::set_spread(real_t p_spread) {
275
spread = p_spread;
276
}
277
278
real_t CPUParticles3D::get_spread() const {
279
return spread;
280
}
281
282
void CPUParticles3D::set_flatness(real_t p_flatness) {
283
flatness = p_flatness;
284
}
285
286
real_t CPUParticles3D::get_flatness() const {
287
return flatness;
288
}
289
290
void CPUParticles3D::set_param_min(Parameter p_param, real_t p_value) {
291
ERR_FAIL_INDEX(p_param, PARAM_MAX);
292
293
parameters_min[p_param] = p_value;
294
if (parameters_min[p_param] > parameters_max[p_param]) {
295
set_param_max(p_param, p_value);
296
}
297
298
update_configuration_warnings();
299
}
300
301
real_t CPUParticles3D::get_param_min(Parameter p_param) const {
302
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
303
304
return parameters_min[p_param];
305
}
306
307
void CPUParticles3D::set_param_max(Parameter p_param, real_t p_value) {
308
ERR_FAIL_INDEX(p_param, PARAM_MAX);
309
310
parameters_max[p_param] = p_value;
311
if (parameters_min[p_param] > parameters_max[p_param]) {
312
set_param_min(p_param, p_value);
313
}
314
315
update_configuration_warnings();
316
}
317
318
real_t CPUParticles3D::get_param_max(Parameter p_param) const {
319
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
320
321
return parameters_max[p_param];
322
}
323
324
static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) {
325
Ref<Curve> curve = p_curve;
326
if (curve.is_null()) {
327
return;
328
}
329
330
curve->ensure_default_setup(p_min, p_max);
331
}
332
333
void CPUParticles3D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) {
334
ERR_FAIL_INDEX(p_param, PARAM_MAX);
335
336
curve_parameters[p_param] = p_curve;
337
338
switch (p_param) {
339
case PARAM_ANGULAR_VELOCITY:
340
case PARAM_ORBIT_VELOCITY:
341
case PARAM_LINEAR_ACCEL:
342
case PARAM_RADIAL_ACCEL:
343
case PARAM_TANGENTIAL_ACCEL:
344
case PARAM_ANGLE:
345
case PARAM_HUE_VARIATION: {
346
_adjust_curve_range(p_curve, -1, 1);
347
} break;
348
case PARAM_DAMPING:
349
case PARAM_SCALE:
350
case PARAM_ANIM_SPEED:
351
case PARAM_ANIM_OFFSET: {
352
_adjust_curve_range(p_curve, 0, 1);
353
} break;
354
case PARAM_INITIAL_LINEAR_VELOCITY:
355
case PARAM_MAX: {
356
// No curve available.
357
} break;
358
}
359
360
update_configuration_warnings();
361
}
362
363
Ref<Curve> CPUParticles3D::get_param_curve(Parameter p_param) const {
364
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Curve>());
365
366
return curve_parameters[p_param];
367
}
368
369
void CPUParticles3D::set_color(const Color &p_color) {
370
color = p_color;
371
}
372
373
Color CPUParticles3D::get_color() const {
374
return color;
375
}
376
377
void CPUParticles3D::set_color_ramp(const Ref<Gradient> &p_ramp) {
378
color_ramp = p_ramp;
379
}
380
381
Ref<Gradient> CPUParticles3D::get_color_ramp() const {
382
return color_ramp;
383
}
384
385
void CPUParticles3D::set_color_initial_ramp(const Ref<Gradient> &p_ramp) {
386
color_initial_ramp = p_ramp;
387
}
388
389
Ref<Gradient> CPUParticles3D::get_color_initial_ramp() const {
390
return color_initial_ramp;
391
}
392
393
void CPUParticles3D::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
394
ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX);
395
particle_flags[p_particle_flag] = p_enable;
396
if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) {
397
notify_property_list_changed();
398
}
399
}
400
401
bool CPUParticles3D::get_particle_flag(ParticleFlags p_particle_flag) const {
402
ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false);
403
return particle_flags[p_particle_flag];
404
}
405
406
void CPUParticles3D::set_emission_shape(EmissionShape p_shape) {
407
ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
408
emission_shape = p_shape;
409
update_gizmos();
410
}
411
412
void CPUParticles3D::set_emission_sphere_radius(real_t p_radius) {
413
emission_sphere_radius = p_radius;
414
update_gizmos();
415
}
416
417
void CPUParticles3D::set_emission_box_extents(Vector3 p_extents) {
418
emission_box_extents = p_extents;
419
update_gizmos();
420
}
421
422
void CPUParticles3D::set_emission_points(const Vector<Vector3> &p_points) {
423
emission_points = p_points;
424
}
425
426
void CPUParticles3D::set_emission_normals(const Vector<Vector3> &p_normals) {
427
emission_normals = p_normals;
428
}
429
430
void CPUParticles3D::set_emission_colors(const Vector<Color> &p_colors) {
431
emission_colors = p_colors;
432
}
433
434
void CPUParticles3D::set_emission_ring_axis(Vector3 p_axis) {
435
emission_ring_axis = p_axis;
436
update_gizmos();
437
}
438
439
void CPUParticles3D::set_emission_ring_height(real_t p_height) {
440
emission_ring_height = p_height;
441
update_gizmos();
442
}
443
444
void CPUParticles3D::set_emission_ring_radius(real_t p_radius) {
445
emission_ring_radius = p_radius;
446
update_gizmos();
447
}
448
449
void CPUParticles3D::set_emission_ring_inner_radius(real_t p_radius) {
450
emission_ring_inner_radius = p_radius;
451
update_gizmos();
452
}
453
454
void CPUParticles3D::set_emission_ring_cone_angle(real_t p_angle) {
455
emission_ring_cone_angle = p_angle;
456
update_gizmos();
457
}
458
459
void CPUParticles3D::set_scale_curve_x(Ref<Curve> p_scale_curve) {
460
scale_curve_x = p_scale_curve;
461
}
462
463
void CPUParticles3D::set_scale_curve_y(Ref<Curve> p_scale_curve) {
464
scale_curve_y = p_scale_curve;
465
}
466
467
void CPUParticles3D::set_scale_curve_z(Ref<Curve> p_scale_curve) {
468
scale_curve_z = p_scale_curve;
469
}
470
471
void CPUParticles3D::set_split_scale(bool p_split_scale) {
472
split_scale = p_split_scale;
473
notify_property_list_changed();
474
}
475
476
real_t CPUParticles3D::get_emission_sphere_radius() const {
477
return emission_sphere_radius;
478
}
479
480
Vector3 CPUParticles3D::get_emission_box_extents() const {
481
return emission_box_extents;
482
}
483
484
Vector<Vector3> CPUParticles3D::get_emission_points() const {
485
return emission_points;
486
}
487
488
Vector<Vector3> CPUParticles3D::get_emission_normals() const {
489
return emission_normals;
490
}
491
492
Vector<Color> CPUParticles3D::get_emission_colors() const {
493
return emission_colors;
494
}
495
496
Vector3 CPUParticles3D::get_emission_ring_axis() const {
497
return emission_ring_axis;
498
}
499
500
real_t CPUParticles3D::get_emission_ring_height() const {
501
return emission_ring_height;
502
}
503
504
real_t CPUParticles3D::get_emission_ring_radius() const {
505
return emission_ring_radius;
506
}
507
508
real_t CPUParticles3D::get_emission_ring_inner_radius() const {
509
return emission_ring_inner_radius;
510
}
511
512
real_t CPUParticles3D::get_emission_ring_cone_angle() const {
513
return emission_ring_cone_angle;
514
}
515
516
CPUParticles3D::EmissionShape CPUParticles3D::get_emission_shape() const {
517
return emission_shape;
518
}
519
520
void CPUParticles3D::set_gravity(const Vector3 &p_gravity) {
521
gravity = p_gravity;
522
}
523
524
Vector3 CPUParticles3D::get_gravity() const {
525
return gravity;
526
}
527
528
Ref<Curve> CPUParticles3D::get_scale_curve_x() const {
529
return scale_curve_x;
530
}
531
532
Ref<Curve> CPUParticles3D::get_scale_curve_y() const {
533
return scale_curve_y;
534
}
535
536
Ref<Curve> CPUParticles3D::get_scale_curve_z() const {
537
return scale_curve_z;
538
}
539
540
bool CPUParticles3D::get_split_scale() {
541
return split_scale;
542
}
543
544
AABB CPUParticles3D::capture_aabb() const {
545
RS::get_singleton()->multimesh_set_custom_aabb(multimesh, AABB());
546
return RS::get_singleton()->multimesh_get_aabb(multimesh);
547
}
548
549
void CPUParticles3D::set_use_fixed_seed(bool p_use_fixed_seed) {
550
if (p_use_fixed_seed == use_fixed_seed) {
551
return;
552
}
553
use_fixed_seed = p_use_fixed_seed;
554
notify_property_list_changed();
555
}
556
557
bool CPUParticles3D::get_use_fixed_seed() const {
558
return use_fixed_seed;
559
}
560
561
void CPUParticles3D::set_seed(uint32_t p_seed) {
562
seed = p_seed;
563
}
564
565
uint32_t CPUParticles3D::get_seed() const {
566
return seed;
567
}
568
569
void CPUParticles3D::request_particles_process(real_t p_requested_process_time) {
570
_requested_process_time = p_requested_process_time;
571
}
572
573
void CPUParticles3D::_validate_property(PropertyInfo &p_property) const {
574
if (Engine::get_singleton()->is_editor_hint() && p_property.name == "emitting") {
575
p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE;
576
}
577
578
if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
579
p_property.usage = PROPERTY_USAGE_NONE;
580
}
581
582
if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
583
p_property.usage = PROPERTY_USAGE_NONE;
584
}
585
586
if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture" || p_property.name == "emission_points") && (emission_shape != EMISSION_SHAPE_POINTS && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS))) {
587
p_property.usage = PROPERTY_USAGE_NONE;
588
}
589
590
if (p_property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
591
p_property.usage = PROPERTY_USAGE_NONE;
592
}
593
594
if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
595
p_property.usage = PROPERTY_USAGE_NONE;
596
}
597
598
if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
599
p_property.usage = PROPERTY_USAGE_NONE;
600
}
601
602
if (p_property.name.begins_with("scale_curve_") && !split_scale) {
603
p_property.usage = PROPERTY_USAGE_NONE;
604
}
605
606
if (p_property.name == "seed" && !use_fixed_seed) {
607
p_property.usage = PROPERTY_USAGE_NONE;
608
}
609
}
610
611
static uint32_t idhash(uint32_t x) {
612
x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
613
x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
614
x = (x >> uint32_t(16)) ^ x;
615
return x;
616
}
617
618
static real_t rand_from_seed(uint32_t &seed) {
619
int k;
620
int s = int(seed);
621
if (s == 0) {
622
s = 305420679;
623
}
624
k = s / 127773;
625
s = 16807 * (s - k * 127773) - 2836 * k;
626
if (s < 0) {
627
s += 2147483647;
628
}
629
seed = uint32_t(s);
630
return (seed % uint32_t(65536)) / 65535.0;
631
}
632
633
void CPUParticles3D::_update_internal() {
634
if (particles.is_empty() || !is_visible_in_tree()) {
635
_set_redraw(false);
636
return;
637
}
638
639
double delta = get_process_delta_time();
640
if (!active && !emitting) {
641
set_process_internal(false);
642
_set_redraw(false);
643
644
//reset variables
645
time = 0;
646
frame_remainder = 0;
647
cycle = 0;
648
return;
649
}
650
_set_redraw(true);
651
652
bool processed = false;
653
654
double frame_time;
655
if (fixed_fps > 0) {
656
frame_time = 1.0 / fixed_fps;
657
} else {
658
frame_time = 1.0 / 30.0;
659
}
660
double todo = _requested_process_time;
661
_requested_process_time = 0.;
662
if (time == 0 && pre_process_time > 0.0) {
663
todo += pre_process_time;
664
}
665
real_t tmp_speed = speed_scale;
666
speed_scale = 1.0;
667
while (todo > 0) {
668
_particles_process(frame_time);
669
todo -= frame_time;
670
}
671
speed_scale = tmp_speed;
672
todo = 0.0;
673
674
if (fixed_fps > 0) {
675
double decr = frame_time;
676
677
double ldelta = delta;
678
if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
679
ldelta = 0.1;
680
} else if (ldelta <= 0.0) { //unlikely but..
681
ldelta = 0.001;
682
}
683
todo = frame_remainder + ldelta;
684
685
while (todo >= frame_time) {
686
_particles_process(frame_time);
687
processed = true;
688
todo -= decr;
689
}
690
691
frame_remainder = todo;
692
693
} else {
694
_particles_process(delta);
695
processed = true;
696
}
697
698
if (processed) {
699
_update_particle_data_buffer();
700
}
701
}
702
703
void CPUParticles3D::_particles_process(double p_delta) {
704
p_delta *= speed_scale;
705
706
int pcount = particles.size();
707
Particle *w = particles.ptrw();
708
709
Particle *parray = w;
710
711
double prev_time = time;
712
time += p_delta;
713
if (time > lifetime) {
714
time = Math::fmod(time, lifetime);
715
cycle++;
716
if (one_shot && cycle > 0) {
717
set_emitting(false);
718
notify_property_list_changed();
719
}
720
}
721
722
Transform3D emission_xform;
723
Basis velocity_xform;
724
if (!local_coords) {
725
emission_xform = get_global_transform_interpolated();
726
velocity_xform = emission_xform.basis;
727
}
728
729
double system_phase = time / lifetime;
730
731
bool should_be_active = false;
732
for (int i = 0; i < pcount; i++) {
733
Particle &p = parray[i];
734
735
if (!emitting && !p.active) {
736
continue;
737
}
738
739
double local_delta = p_delta;
740
741
// The phase is a ratio between 0 (birth) and 1 (end of life) for each particle.
742
// While we use time in tests later on, for randomness we use the phase as done in the
743
// original shader code, and we later multiply by lifetime to get the time.
744
double restart_phase = double(i) / double(pcount);
745
746
if (randomness_ratio > 0.0) {
747
uint32_t _seed = cycle;
748
if (restart_phase >= system_phase) {
749
_seed -= uint32_t(1);
750
}
751
_seed *= uint32_t(pcount);
752
_seed += uint32_t(i);
753
double random = double(idhash(_seed) % uint32_t(65536)) / 65536.0;
754
restart_phase += randomness_ratio * random * 1.0 / double(pcount);
755
}
756
757
restart_phase *= (1.0 - explosiveness_ratio);
758
double restart_time = restart_phase * lifetime;
759
bool restart = false;
760
761
if (time > prev_time) {
762
// restart_time >= prev_time is used so particles emit in the first frame they are processed
763
764
if (restart_time >= prev_time && restart_time < time) {
765
restart = true;
766
if (fractional_delta) {
767
local_delta = time - restart_time;
768
}
769
}
770
771
} else if (local_delta > 0.0) {
772
if (restart_time >= prev_time) {
773
restart = true;
774
if (fractional_delta) {
775
local_delta = lifetime - restart_time + time;
776
}
777
778
} else if (restart_time < time) {
779
restart = true;
780
if (fractional_delta) {
781
local_delta = time - restart_time;
782
}
783
}
784
}
785
786
if (p.time * (1.0 - explosiveness_ratio) > p.lifetime) {
787
restart = true;
788
}
789
790
float tv = 0.0;
791
792
if (restart) {
793
if (!emitting) {
794
p.active = false;
795
continue;
796
}
797
p.active = true;
798
799
/*real_t tex_linear_velocity = 0;
800
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
801
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(0);
802
}*/
803
804
real_t tex_angle = 1.0;
805
if (curve_parameters[PARAM_ANGLE].is_valid()) {
806
tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv);
807
}
808
809
real_t tex_anim_offset = 1.0;
810
if (curve_parameters[PARAM_ANGLE].is_valid()) {
811
tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv);
812
}
813
814
p.seed = seed + uint32_t(1) + i + cycle * pcount;
815
rng->set_seed(p.seed);
816
p.angle_rand = rng->randf();
817
p.scale_rand = rng->randf();
818
p.hue_rot_rand = rng->randf();
819
p.anim_offset_rand = rng->randf();
820
821
if (color_initial_ramp.is_valid()) {
822
p.start_color_rand = color_initial_ramp->get_color_at_offset(rng->randf());
823
} else {
824
p.start_color_rand = Color(1, 1, 1, 1);
825
}
826
827
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
828
real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg_to_rad((rng->randf() * 2.0 - 1.0) * spread);
829
Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
830
p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], rng->randf());
831
} else {
832
//initiate velocity spread in 3D
833
real_t angle1_rad = Math::deg_to_rad((rng->randf() * (real_t)2.0 - (real_t)1.0) * spread);
834
real_t angle2_rad = Math::deg_to_rad((rng->randf() * (real_t)2.0 - (real_t)1.0) * ((real_t)1.0 - flatness) * spread);
835
836
Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad));
837
Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad));
838
Vector3 spread_direction = Vector3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);
839
Vector3 direction_nrm = direction;
840
if (direction_nrm.length_squared() > 0) {
841
direction_nrm.normalize();
842
} else {
843
direction_nrm = Vector3(0, 0, 1);
844
}
845
// rotate spread to direction
846
Vector3 binormal = Vector3(0.0, 1.0, 0.0).cross(direction_nrm);
847
if (binormal.length_squared() < 0.00000001) {
848
// direction is parallel to Y. Choose Z as the binormal.
849
binormal = Vector3(0.0, 0.0, 1.0);
850
}
851
binormal.normalize();
852
Vector3 normal = binormal.cross(direction_nrm);
853
spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;
854
p.velocity = spread_direction * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], rng->randf());
855
}
856
857
real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
858
p.custom[0] = Math::deg_to_rad(base_angle); //angle
859
p.custom[1] = 0.0; //phase
860
p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand); //animation offset (0-1)
861
p.custom[3] = (1.0 - rng->randf() * lifetime_randomness);
862
p.transform = Transform3D();
863
p.time = 0;
864
p.lifetime = lifetime * p.custom[3];
865
p.base_color = Color(1, 1, 1, 1);
866
867
switch (emission_shape) {
868
case EMISSION_SHAPE_POINT: {
869
//do none
870
} break;
871
case EMISSION_SHAPE_SPHERE: {
872
real_t s = 2.0 * rng->randf() - 1.0;
873
real_t t = Math::TAU * rng->randf();
874
real_t x = rng->randf();
875
real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
876
p.transform.origin = Vector3(0, 0, 0).lerp(Vector3(radius * Math::cos(t), radius * Math::sin(t), emission_sphere_radius * s), x);
877
} break;
878
case EMISSION_SHAPE_SPHERE_SURFACE: {
879
real_t s = 2.0 * rng->randf() - 1.0;
880
real_t t = Math::TAU * rng->randf();
881
real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
882
p.transform.origin = Vector3(radius * Math::cos(t), radius * Math::sin(t), emission_sphere_radius * s);
883
} break;
884
case EMISSION_SHAPE_BOX: {
885
p.transform.origin = Vector3(rng->randf() * 2.0 - 1.0, rng->randf() * 2.0 - 1.0, rng->randf() * 2.0 - 1.0) * emission_box_extents;
886
} break;
887
case EMISSION_SHAPE_POINTS:
888
case EMISSION_SHAPE_DIRECTED_POINTS: {
889
int pc = emission_points.size();
890
if (pc == 0) {
891
break;
892
}
893
894
int random_idx = Math::rand() % pc;
895
896
p.transform.origin = emission_points.get(random_idx);
897
898
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
899
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
900
Vector3 normal = emission_normals.get(random_idx);
901
Vector2 normal_2d(normal.x, normal.y);
902
Transform2D m2;
903
m2.columns[0] = normal_2d;
904
m2.columns[1] = normal_2d.orthogonal();
905
Vector2 velocity_2d(p.velocity.x, p.velocity.y);
906
velocity_2d = m2.basis_xform(velocity_2d);
907
p.velocity.x = velocity_2d.x;
908
p.velocity.y = velocity_2d.y;
909
} else {
910
Vector3 normal = emission_normals.get(random_idx);
911
Vector3 v0 = Math::abs(normal.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(0, 1.0, 0.0);
912
Vector3 tangent = v0.cross(normal).normalized();
913
Vector3 bitangent = tangent.cross(normal).normalized();
914
Basis m3;
915
m3.set_column(0, tangent);
916
m3.set_column(1, bitangent);
917
m3.set_column(2, normal);
918
p.velocity = m3.xform(p.velocity);
919
}
920
}
921
922
if (emission_colors.size() == pc) {
923
p.base_color = emission_colors.get(random_idx);
924
}
925
} break;
926
case EMISSION_SHAPE_RING: {
927
real_t radius_clamped = MAX(0.001, emission_ring_radius);
928
real_t top_radius = MAX(radius_clamped - Math::tan(Math::deg_to_rad(90.0 - emission_ring_cone_angle)) * emission_ring_height, 0.0);
929
real_t y_pos = rng->randf();
930
real_t skew = MAX(MIN(radius_clamped, top_radius) / MAX(radius_clamped, top_radius), 0.5);
931
y_pos = radius_clamped < top_radius ? Math::pow(y_pos, skew) : 1.0 - Math::pow(y_pos, skew);
932
real_t ring_random_angle = rng->randf() * Math::TAU;
933
real_t ring_random_radius = Math::sqrt(rng->randf() * (radius_clamped * radius_clamped - emission_ring_inner_radius * emission_ring_inner_radius) + emission_ring_inner_radius * emission_ring_inner_radius);
934
ring_random_radius = Math::lerp(ring_random_radius, ring_random_radius * (top_radius / radius_clamped), y_pos);
935
Vector3 axis = emission_ring_axis == Vector3(0.0, 0.0, 0.0) ? Vector3(0.0, 0.0, 1.0) : emission_ring_axis.normalized();
936
Vector3 ortho_axis;
937
if (axis.abs() == Vector3(1.0, 0.0, 0.0)) {
938
ortho_axis = Vector3(0.0, 1.0, 0.0).cross(axis);
939
} else {
940
ortho_axis = Vector3(1.0, 0.0, 0.0).cross(axis);
941
}
942
ortho_axis = ortho_axis.normalized();
943
ortho_axis.rotate(axis, ring_random_angle);
944
ortho_axis = ortho_axis.normalized();
945
p.transform.origin = ortho_axis * ring_random_radius + (y_pos * emission_ring_height - emission_ring_height / 2.0) * axis;
946
} break;
947
case EMISSION_SHAPE_MAX: { // Max value for validity check.
948
break;
949
}
950
}
951
952
if (!local_coords) {
953
p.velocity = velocity_xform.xform(p.velocity);
954
p.transform = emission_xform * p.transform;
955
}
956
957
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
958
p.velocity.z = 0.0;
959
p.transform.origin.z = 0.0;
960
}
961
962
} else if (!p.active) {
963
continue;
964
} else if (p.time > p.lifetime) {
965
p.active = false;
966
tv = 1.0;
967
} else {
968
uint32_t alt_seed = p.seed;
969
970
p.time += local_delta;
971
p.custom[1] = p.time / lifetime;
972
tv = p.time / p.lifetime;
973
974
real_t tex_linear_velocity = 1.0;
975
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
976
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(tv);
977
}
978
979
real_t tex_orbit_velocity = 1.0;
980
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
981
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
982
tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->sample(tv);
983
}
984
}
985
986
real_t tex_angular_velocity = 1.0;
987
if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
988
tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->sample(tv);
989
}
990
991
real_t tex_linear_accel = 1.0;
992
if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
993
tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->sample(tv);
994
}
995
996
real_t tex_tangential_accel = 1.0;
997
if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
998
tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->sample(tv);
999
}
1000
1001
real_t tex_radial_accel = 1.0;
1002
if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
1003
tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->sample(tv);
1004
}
1005
1006
real_t tex_damping = 1.0;
1007
if (curve_parameters[PARAM_DAMPING].is_valid()) {
1008
tex_damping = curve_parameters[PARAM_DAMPING]->sample(tv);
1009
}
1010
1011
real_t tex_angle = 1.0;
1012
if (curve_parameters[PARAM_ANGLE].is_valid()) {
1013
tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv);
1014
}
1015
real_t tex_anim_speed = 1.0;
1016
if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
1017
tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->sample(tv);
1018
}
1019
1020
real_t tex_anim_offset = 1.0;
1021
if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
1022
tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->sample(tv);
1023
}
1024
1025
Vector3 force = gravity;
1026
Vector3 position = p.transform.origin;
1027
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
1028
position.z = 0.0;
1029
}
1030
//apply linear acceleration
1031
force += p.velocity.length() > 0.0 ? p.velocity.normalized() * tex_linear_accel * Math::lerp(parameters_min[PARAM_LINEAR_ACCEL], parameters_max[PARAM_LINEAR_ACCEL], rand_from_seed(alt_seed)) : Vector3();
1032
//apply radial acceleration
1033
Vector3 org = emission_xform.origin;
1034
Vector3 diff = position - org;
1035
force += diff.length() > 0.0 ? diff.normalized() * (tex_radial_accel)*Math::lerp(parameters_min[PARAM_RADIAL_ACCEL], parameters_max[PARAM_RADIAL_ACCEL], rand_from_seed(alt_seed)) : Vector3();
1036
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
1037
Vector2 yx = Vector2(diff.y, diff.x);
1038
Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized();
1039
force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector3();
1040
1041
} else {
1042
Vector3 crossDiff = diff.normalized().cross(gravity.normalized());
1043
force += crossDiff.length() > 0.0 ? crossDiff.normalized() * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector3();
1044
}
1045
//apply attractor forces
1046
p.velocity += force * local_delta;
1047
//orbit velocity
1048
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
1049
real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed));
1050
if (orbit_amount != 0.0) {
1051
real_t ang = orbit_amount * local_delta * Math::TAU;
1052
// Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix,
1053
// but we use -ang here to reproduce its behavior.
1054
Transform2D rot = Transform2D(-ang, Vector2());
1055
Vector2 rotv = rot.basis_xform(Vector2(diff.x, diff.y));
1056
p.transform.origin -= Vector3(diff.x, diff.y, 0);
1057
p.transform.origin += Vector3(rotv.x, rotv.y, 0);
1058
}
1059
}
1060
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
1061
p.velocity = p.velocity.normalized() * tex_linear_velocity;
1062
}
1063
1064
if (parameters_max[PARAM_DAMPING] + tex_damping > 0.0) {
1065
real_t v = p.velocity.length();
1066
real_t damp = tex_damping * Math::lerp(parameters_min[PARAM_DAMPING], parameters_max[PARAM_DAMPING], rand_from_seed(alt_seed));
1067
v -= damp * local_delta;
1068
if (v < 0.0) {
1069
p.velocity = Vector3();
1070
} else {
1071
p.velocity = p.velocity.normalized() * v;
1072
}
1073
}
1074
real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
1075
base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed));
1076
p.custom[0] = Math::deg_to_rad(base_angle); //angle
1077
p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + tv * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed)); //angle
1078
}
1079
//apply color
1080
//apply hue rotation
1081
1082
Vector3 tex_scale = Vector3(1.0, 1.0, 1.0);
1083
if (split_scale) {
1084
if (scale_curve_x.is_valid()) {
1085
tex_scale.x = scale_curve_x->sample(tv);
1086
} else {
1087
tex_scale.x = 1.0;
1088
}
1089
if (scale_curve_y.is_valid()) {
1090
tex_scale.y = scale_curve_y->sample(tv);
1091
} else {
1092
tex_scale.y = 1.0;
1093
}
1094
if (scale_curve_z.is_valid()) {
1095
tex_scale.z = scale_curve_z->sample(tv);
1096
} else {
1097
tex_scale.z = 1.0;
1098
}
1099
} else {
1100
if (curve_parameters[PARAM_SCALE].is_valid()) {
1101
float tmp_scale = curve_parameters[PARAM_SCALE]->sample(tv);
1102
tex_scale.x = tmp_scale;
1103
tex_scale.y = tmp_scale;
1104
tex_scale.z = tmp_scale;
1105
}
1106
}
1107
1108
real_t tex_hue_variation = 0.0;
1109
if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
1110
tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->sample(tv);
1111
}
1112
1113
real_t hue_rot_angle = (tex_hue_variation)*Math::TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand);
1114
real_t hue_rot_c = Math::cos(hue_rot_angle);
1115
real_t hue_rot_s = Math::sin(hue_rot_angle);
1116
1117
Basis hue_rot_mat;
1118
{
1119
Basis mat1(0.299, 0.587, 0.114, 0.299, 0.587, 0.114, 0.299, 0.587, 0.114);
1120
Basis mat2(0.701, -0.587, -0.114, -0.299, 0.413, -0.114, -0.300, -0.588, 0.886);
1121
Basis mat3(0.168, 0.330, -0.497, -0.328, 0.035, 0.292, 1.250, -1.050, -0.203);
1122
1123
for (int j = 0; j < 3; j++) {
1124
hue_rot_mat[j] = mat1[j] + mat2[j] * hue_rot_c + mat3[j] * hue_rot_s;
1125
}
1126
}
1127
1128
if (color_ramp.is_valid()) {
1129
p.color = color_ramp->get_color_at_offset(tv) * color;
1130
} else {
1131
p.color = color;
1132
}
1133
1134
Vector3 color_rgb = hue_rot_mat.xform_inv(Vector3(p.color.r, p.color.g, p.color.b));
1135
p.color.r = color_rgb.x;
1136
p.color.g = color_rgb.y;
1137
p.color.b = color_rgb.z;
1138
1139
p.color *= p.base_color * p.start_color_rand;
1140
1141
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
1142
if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
1143
if (p.velocity.length() > 0.0) {
1144
p.transform.basis.set_column(1, p.velocity.normalized());
1145
} else {
1146
p.transform.basis.set_column(1, p.transform.basis.get_column(1));
1147
}
1148
p.transform.basis.set_column(0, p.transform.basis.get_column(1).cross(p.transform.basis.get_column(2)).normalized());
1149
p.transform.basis.set_column(2, Vector3(0, 0, 1));
1150
1151
} else {
1152
p.transform.basis.set_column(0, Vector3(Math::cos(p.custom[0]), -Math::sin(p.custom[0]), 0.0));
1153
p.transform.basis.set_column(1, Vector3(Math::sin(p.custom[0]), Math::cos(p.custom[0]), 0.0));
1154
p.transform.basis.set_column(2, Vector3(0, 0, 1));
1155
}
1156
1157
} else {
1158
//orient particle Y towards velocity
1159
if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
1160
if (p.velocity.length() > 0.0) {
1161
p.transform.basis.set_column(1, p.velocity.normalized());
1162
} else {
1163
p.transform.basis.set_column(1, p.transform.basis.get_column(1).normalized());
1164
}
1165
if (p.transform.basis.get_column(1) == p.transform.basis.get_column(0)) {
1166
p.transform.basis.set_column(0, p.transform.basis.get_column(1).cross(p.transform.basis.get_column(2)).normalized());
1167
p.transform.basis.set_column(2, p.transform.basis.get_column(0).cross(p.transform.basis.get_column(1)).normalized());
1168
} else {
1169
p.transform.basis.set_column(2, p.transform.basis.get_column(0).cross(p.transform.basis.get_column(1)).normalized());
1170
p.transform.basis.set_column(0, p.transform.basis.get_column(1).cross(p.transform.basis.get_column(2)).normalized());
1171
}
1172
} else {
1173
p.transform.basis.orthonormalize();
1174
}
1175
1176
//turn particle by rotation in Y
1177
if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) {
1178
Basis rot_y(Vector3(0, 1, 0), p.custom[0]);
1179
p.transform.basis = rot_y;
1180
}
1181
}
1182
1183
p.transform.basis = p.transform.basis.orthonormalized();
1184
//scale by scale
1185
1186
Vector3 base_scale = tex_scale * Math::lerp(parameters_min[PARAM_SCALE], parameters_max[PARAM_SCALE], p.scale_rand);
1187
if (base_scale.x < CMP_EPSILON) {
1188
base_scale.x = CMP_EPSILON;
1189
}
1190
if (base_scale.y < CMP_EPSILON) {
1191
base_scale.y = CMP_EPSILON;
1192
}
1193
if (base_scale.z < CMP_EPSILON) {
1194
base_scale.z = CMP_EPSILON;
1195
}
1196
1197
p.transform.basis.scale(base_scale);
1198
1199
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
1200
p.velocity.z = 0.0;
1201
p.transform.origin.z = 0.0;
1202
}
1203
1204
p.transform.origin += p.velocity * local_delta;
1205
1206
should_be_active = true;
1207
}
1208
if (!Math::is_equal_approx(time, 0.0) && active && !should_be_active) {
1209
active = false;
1210
emit_signal(SceneStringName(finished));
1211
}
1212
}
1213
1214
void CPUParticles3D::_update_particle_data_buffer() {
1215
MutexLock lock(update_mutex);
1216
1217
int pc = particles.size();
1218
1219
int *ow;
1220
int *order = nullptr;
1221
1222
float *w = particle_data.ptrw();
1223
const Particle *r = particles.ptr();
1224
float *ptr = w;
1225
1226
if (draw_order != DRAW_ORDER_INDEX) {
1227
ow = particle_order.ptrw();
1228
order = ow;
1229
1230
for (int i = 0; i < pc; i++) {
1231
order[i] = i;
1232
}
1233
if (draw_order == DRAW_ORDER_LIFETIME) {
1234
SortArray<int, SortLifetime> sorter;
1235
sorter.compare.particles = r;
1236
sorter.sort(order, pc);
1237
} else if (draw_order == DRAW_ORDER_VIEW_DEPTH) {
1238
ERR_FAIL_NULL(get_viewport());
1239
Camera3D *c = get_viewport()->get_camera_3d();
1240
if (c) {
1241
Vector3 dir = c->get_global_transform().basis.get_column(2); //far away to close
1242
1243
if (local_coords) {
1244
// will look different from Particles in editor as this is based on the camera in the scenetree
1245
// and not the editor camera
1246
dir = inv_emission_transform.xform(dir).normalized();
1247
} else {
1248
dir = dir.normalized();
1249
}
1250
1251
SortArray<int, SortAxis> sorter;
1252
sorter.compare.particles = r;
1253
sorter.compare.axis = dir;
1254
sorter.sort(order, pc);
1255
}
1256
}
1257
}
1258
1259
for (int i = 0; i < pc; i++) {
1260
int idx = order ? order[i] : i;
1261
1262
Transform3D t = r[idx].transform;
1263
1264
if (!local_coords) {
1265
t = inv_emission_transform * t;
1266
}
1267
1268
if (r[idx].active) {
1269
ptr[0] = t.basis.rows[0][0];
1270
ptr[1] = t.basis.rows[0][1];
1271
ptr[2] = t.basis.rows[0][2];
1272
ptr[3] = t.origin.x;
1273
ptr[4] = t.basis.rows[1][0];
1274
ptr[5] = t.basis.rows[1][1];
1275
ptr[6] = t.basis.rows[1][2];
1276
ptr[7] = t.origin.y;
1277
ptr[8] = t.basis.rows[2][0];
1278
ptr[9] = t.basis.rows[2][1];
1279
ptr[10] = t.basis.rows[2][2];
1280
ptr[11] = t.origin.z;
1281
} else {
1282
memset(ptr, 0, sizeof(float) * 12);
1283
}
1284
1285
Color c = r[idx].color;
1286
1287
ptr[12] = c.r;
1288
ptr[13] = c.g;
1289
ptr[14] = c.b;
1290
ptr[15] = c.a;
1291
1292
ptr[16] = r[idx].custom[0];
1293
ptr[17] = r[idx].custom[1];
1294
ptr[18] = r[idx].custom[2];
1295
ptr[19] = r[idx].custom[3];
1296
1297
ptr += 20;
1298
}
1299
1300
can_update.set();
1301
}
1302
1303
void CPUParticles3D::_set_redraw(bool p_redraw) {
1304
if (redraw == p_redraw) {
1305
return;
1306
}
1307
redraw = p_redraw;
1308
1309
{
1310
MutexLock lock(update_mutex);
1311
1312
if (redraw) {
1313
RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &CPUParticles3D::_update_render_thread));
1314
RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
1315
RS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
1316
} else {
1317
if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &CPUParticles3D::_update_render_thread))) {
1318
RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &CPUParticles3D::_update_render_thread));
1319
}
1320
RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
1321
RS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
1322
}
1323
}
1324
}
1325
1326
void CPUParticles3D::_update_render_thread() {
1327
MutexLock lock(update_mutex);
1328
1329
if (can_update.is_set()) {
1330
RS::get_singleton()->multimesh_set_buffer(multimesh, particle_data);
1331
can_update.clear(); //wait for next time
1332
}
1333
}
1334
1335
void CPUParticles3D::_notification(int p_what) {
1336
switch (p_what) {
1337
case NOTIFICATION_ENTER_TREE: {
1338
set_process_internal(emitting);
1339
1340
// first update before rendering to avoid one frame delay after emitting starts
1341
if (emitting && (time == 0)) {
1342
_update_internal();
1343
}
1344
} break;
1345
1346
case NOTIFICATION_EXIT_TREE: {
1347
_set_redraw(false);
1348
} break;
1349
1350
case NOTIFICATION_VISIBILITY_CHANGED: {
1351
// first update before rendering to avoid one frame delay after emitting starts
1352
if (emitting && (time == 0)) {
1353
_update_internal();
1354
}
1355
} break;
1356
1357
case NOTIFICATION_INTERNAL_PROCESS: {
1358
_update_internal();
1359
} break;
1360
1361
case NOTIFICATION_TRANSFORM_CHANGED: {
1362
inv_emission_transform = get_global_transform().affine_inverse();
1363
1364
if (!local_coords) {
1365
int pc = particles.size();
1366
1367
float *w = particle_data.ptrw();
1368
const Particle *r = particles.ptr();
1369
float *ptr = w;
1370
1371
for (int i = 0; i < pc; i++) {
1372
Transform3D t = inv_emission_transform * r[i].transform;
1373
1374
if (r[i].active) {
1375
ptr[0] = t.basis.rows[0][0];
1376
ptr[1] = t.basis.rows[0][1];
1377
ptr[2] = t.basis.rows[0][2];
1378
ptr[3] = t.origin.x;
1379
ptr[4] = t.basis.rows[1][0];
1380
ptr[5] = t.basis.rows[1][1];
1381
ptr[6] = t.basis.rows[1][2];
1382
ptr[7] = t.origin.y;
1383
ptr[8] = t.basis.rows[2][0];
1384
ptr[9] = t.basis.rows[2][1];
1385
ptr[10] = t.basis.rows[2][2];
1386
ptr[11] = t.origin.z;
1387
} else {
1388
memset(ptr, 0, sizeof(float) * 12);
1389
}
1390
1391
ptr += 20;
1392
}
1393
1394
can_update.set();
1395
}
1396
} break;
1397
}
1398
}
1399
1400
void CPUParticles3D::convert_from_particles(Node *p_particles) {
1401
GPUParticles3D *gpu_particles = Object::cast_to<GPUParticles3D>(p_particles);
1402
ERR_FAIL_NULL_MSG(gpu_particles, "Only GPUParticles3D nodes can be converted to CPUParticles3D.");
1403
1404
set_emitting(gpu_particles->is_emitting());
1405
set_amount(gpu_particles->get_amount());
1406
set_lifetime(gpu_particles->get_lifetime());
1407
set_one_shot(gpu_particles->get_one_shot());
1408
set_pre_process_time(gpu_particles->get_pre_process_time());
1409
set_explosiveness_ratio(gpu_particles->get_explosiveness_ratio());
1410
set_randomness_ratio(gpu_particles->get_randomness_ratio());
1411
set_visibility_aabb(gpu_particles->get_visibility_aabb());
1412
set_use_local_coordinates(gpu_particles->get_use_local_coordinates());
1413
set_fixed_fps(gpu_particles->get_fixed_fps());
1414
set_fractional_delta(gpu_particles->get_fractional_delta());
1415
set_speed_scale(gpu_particles->get_speed_scale());
1416
set_draw_order(DrawOrder(gpu_particles->get_draw_order()));
1417
set_mesh(gpu_particles->get_draw_pass_mesh(0));
1418
1419
Ref<ParticleProcessMaterial> material = gpu_particles->get_process_material();
1420
if (material.is_null()) {
1421
return;
1422
}
1423
1424
set_direction(material->get_direction());
1425
set_spread(material->get_spread());
1426
set_flatness(material->get_flatness());
1427
1428
set_color(material->get_color());
1429
1430
Ref<GradientTexture1D> gt = material->get_color_ramp();
1431
if (gt.is_valid()) {
1432
set_color_ramp(gt->get_gradient());
1433
}
1434
1435
Ref<GradientTexture1D> gti = material->get_color_initial_ramp();
1436
if (gti.is_valid()) {
1437
set_color_initial_ramp(gti->get_gradient());
1438
}
1439
1440
set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
1441
set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ROTATE_Y));
1442
set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z));
1443
1444
set_emission_shape(EmissionShape(material->get_emission_shape()));
1445
set_emission_sphere_radius(material->get_emission_sphere_radius());
1446
set_emission_box_extents(material->get_emission_box_extents());
1447
set_emission_ring_height(material->get_emission_ring_height());
1448
set_emission_ring_radius(material->get_emission_ring_radius());
1449
set_emission_ring_inner_radius(material->get_emission_ring_inner_radius());
1450
set_emission_ring_cone_angle(material->get_emission_ring_cone_angle());
1451
1452
Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE);
1453
if (scale3D.is_valid()) {
1454
split_scale = true;
1455
scale_curve_x = scale3D->get_curve_x();
1456
scale_curve_y = scale3D->get_curve_y();
1457
scale_curve_z = scale3D->get_curve_z();
1458
}
1459
1460
set_gravity(material->get_gravity());
1461
set_lifetime_randomness(material->get_lifetime_randomness());
1462
1463
#define CONVERT_PARAM(m_param) \
1464
set_param_min(m_param, material->get_param_min(ParticleProcessMaterial::m_param)); \
1465
{ \
1466
Ref<CurveTexture> ctex = material->get_param_texture(ParticleProcessMaterial::m_param); \
1467
if (ctex.is_valid()) \
1468
set_param_curve(m_param, ctex->get_curve()); \
1469
} \
1470
set_param_max(m_param, material->get_param_max(ParticleProcessMaterial::m_param));
1471
1472
CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
1473
CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
1474
CONVERT_PARAM(PARAM_ORBIT_VELOCITY);
1475
CONVERT_PARAM(PARAM_LINEAR_ACCEL);
1476
CONVERT_PARAM(PARAM_RADIAL_ACCEL);
1477
CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL);
1478
CONVERT_PARAM(PARAM_DAMPING);
1479
CONVERT_PARAM(PARAM_ANGLE);
1480
CONVERT_PARAM(PARAM_SCALE);
1481
CONVERT_PARAM(PARAM_HUE_VARIATION);
1482
CONVERT_PARAM(PARAM_ANIM_SPEED);
1483
CONVERT_PARAM(PARAM_ANIM_OFFSET);
1484
1485
#undef CONVERT_PARAM
1486
}
1487
1488
void CPUParticles3D::_bind_methods() {
1489
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles3D::set_emitting);
1490
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles3D::set_amount);
1491
ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles3D::set_lifetime);
1492
ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles3D::set_one_shot);
1493
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles3D::set_pre_process_time);
1494
ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles3D::set_explosiveness_ratio);
1495
ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles3D::set_randomness_ratio);
1496
ClassDB::bind_method(D_METHOD("set_visibility_aabb", "aabb"), &CPUParticles3D::set_visibility_aabb);
1497
ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "random"), &CPUParticles3D::set_lifetime_randomness);
1498
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles3D::set_use_local_coordinates);
1499
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles3D::set_fixed_fps);
1500
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &CPUParticles3D::set_fractional_delta);
1501
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &CPUParticles3D::set_speed_scale);
1502
1503
ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles3D::is_emitting);
1504
ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles3D::get_amount);
1505
ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles3D::get_lifetime);
1506
ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles3D::get_one_shot);
1507
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles3D::get_pre_process_time);
1508
ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles3D::get_explosiveness_ratio);
1509
ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles3D::get_randomness_ratio);
1510
ClassDB::bind_method(D_METHOD("get_visibility_aabb"), &CPUParticles3D::get_visibility_aabb);
1511
ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &CPUParticles3D::get_lifetime_randomness);
1512
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles3D::get_use_local_coordinates);
1513
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles3D::get_fixed_fps);
1514
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &CPUParticles3D::get_fractional_delta);
1515
ClassDB::bind_method(D_METHOD("get_speed_scale"), &CPUParticles3D::get_speed_scale);
1516
1517
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &CPUParticles3D::set_draw_order);
1518
1519
ClassDB::bind_method(D_METHOD("get_draw_order"), &CPUParticles3D::get_draw_order);
1520
1521
ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CPUParticles3D::set_mesh);
1522
ClassDB::bind_method(D_METHOD("get_mesh"), &CPUParticles3D::get_mesh);
1523
1524
ClassDB::bind_method(D_METHOD("set_use_fixed_seed", "use_fixed_seed"), &CPUParticles3D::set_use_fixed_seed);
1525
ClassDB::bind_method(D_METHOD("get_use_fixed_seed"), &CPUParticles3D::get_use_fixed_seed);
1526
1527
ClassDB::bind_method(D_METHOD("set_seed", "seed"), &CPUParticles3D::set_seed);
1528
ClassDB::bind_method(D_METHOD("get_seed"), &CPUParticles3D::get_seed);
1529
1530
ClassDB::bind_method(D_METHOD("restart", "keep_seed"), &CPUParticles3D::restart, DEFVAL(false));
1531
ClassDB::bind_method(D_METHOD("request_particles_process", "process_time"), &CPUParticles3D::request_particles_process);
1532
ClassDB::bind_method(D_METHOD("capture_aabb"), &CPUParticles3D::capture_aabb);
1533
1534
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
1535
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); // FIXME: Evaluate support for `exp` in integer properties, or remove this.
1536
ADD_GROUP("Time", "");
1537
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime");
1538
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
1539
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,10.0,0.01,or_greater,exp,suffix:s"), "set_pre_process_time", "get_pre_process_time");
1540
1541
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
1542
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
1543
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
1544
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_fixed_seed"), "set_use_fixed_seed", "get_use_fixed_seed");
1545
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed", PROPERTY_HINT_RANGE, "0," + itos(UINT32_MAX) + ",1"), "set_seed", "get_seed");
1546
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
1547
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps");
1548
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
1549
ADD_GROUP("Drawing", "");
1550
ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_visibility_aabb", "get_visibility_aabb");
1551
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
1552
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
1553
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, Mesh::get_class_static()), "set_mesh", "get_mesh");
1554
1555
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
1556
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
1557
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
1558
1559
ADD_PROPERTY_DEFAULT("seed", 0);
1560
1561
////////////////////////////////
1562
1563
ClassDB::bind_method(D_METHOD("set_direction", "direction"), &CPUParticles3D::set_direction);
1564
ClassDB::bind_method(D_METHOD("get_direction"), &CPUParticles3D::get_direction);
1565
1566
ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles3D::set_spread);
1567
ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles3D::get_spread);
1568
1569
ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &CPUParticles3D::set_flatness);
1570
ClassDB::bind_method(D_METHOD("get_flatness"), &CPUParticles3D::get_flatness);
1571
1572
ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &CPUParticles3D::set_param_min);
1573
ClassDB::bind_method(D_METHOD("get_param_min", "param"), &CPUParticles3D::get_param_min);
1574
1575
ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &CPUParticles3D::set_param_max);
1576
ClassDB::bind_method(D_METHOD("get_param_max", "param"), &CPUParticles3D::get_param_max);
1577
1578
ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles3D::set_param_curve);
1579
ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles3D::get_param_curve);
1580
1581
ClassDB::bind_method(D_METHOD("set_color", "color"), &CPUParticles3D::set_color);
1582
ClassDB::bind_method(D_METHOD("get_color"), &CPUParticles3D::get_color);
1583
1584
ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles3D::set_color_ramp);
1585
ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles3D::get_color_ramp);
1586
1587
ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &CPUParticles3D::set_color_initial_ramp);
1588
ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &CPUParticles3D::get_color_initial_ramp);
1589
1590
ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &CPUParticles3D::set_particle_flag);
1591
ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &CPUParticles3D::get_particle_flag);
1592
1593
ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles3D::set_emission_shape);
1594
ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles3D::get_emission_shape);
1595
1596
ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &CPUParticles3D::set_emission_sphere_radius);
1597
ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &CPUParticles3D::get_emission_sphere_radius);
1598
1599
ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &CPUParticles3D::set_emission_box_extents);
1600
ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &CPUParticles3D::get_emission_box_extents);
1601
1602
ClassDB::bind_method(D_METHOD("set_emission_points", "array"), &CPUParticles3D::set_emission_points);
1603
ClassDB::bind_method(D_METHOD("get_emission_points"), &CPUParticles3D::get_emission_points);
1604
1605
ClassDB::bind_method(D_METHOD("set_emission_normals", "array"), &CPUParticles3D::set_emission_normals);
1606
ClassDB::bind_method(D_METHOD("get_emission_normals"), &CPUParticles3D::get_emission_normals);
1607
1608
ClassDB::bind_method(D_METHOD("set_emission_colors", "array"), &CPUParticles3D::set_emission_colors);
1609
ClassDB::bind_method(D_METHOD("get_emission_colors"), &CPUParticles3D::get_emission_colors);
1610
1611
ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &CPUParticles3D::set_emission_ring_axis);
1612
ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &CPUParticles3D::get_emission_ring_axis);
1613
1614
ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &CPUParticles3D::set_emission_ring_height);
1615
ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &CPUParticles3D::get_emission_ring_height);
1616
1617
ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &CPUParticles3D::set_emission_ring_radius);
1618
ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &CPUParticles3D::get_emission_ring_radius);
1619
1620
ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &CPUParticles3D::set_emission_ring_inner_radius);
1621
ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &CPUParticles3D::get_emission_ring_inner_radius);
1622
1623
ClassDB::bind_method(D_METHOD("set_emission_ring_cone_angle", "cone_angle"), &CPUParticles3D::set_emission_ring_cone_angle);
1624
ClassDB::bind_method(D_METHOD("get_emission_ring_cone_angle"), &CPUParticles3D::get_emission_ring_cone_angle);
1625
1626
ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles3D::get_gravity);
1627
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles3D::set_gravity);
1628
1629
ClassDB::bind_method(D_METHOD("get_split_scale"), &CPUParticles3D::get_split_scale);
1630
ClassDB::bind_method(D_METHOD("set_split_scale", "split_scale"), &CPUParticles3D::set_split_scale);
1631
1632
ClassDB::bind_method(D_METHOD("get_scale_curve_x"), &CPUParticles3D::get_scale_curve_x);
1633
ClassDB::bind_method(D_METHOD("set_scale_curve_x", "scale_curve"), &CPUParticles3D::set_scale_curve_x);
1634
1635
ClassDB::bind_method(D_METHOD("get_scale_curve_y"), &CPUParticles3D::get_scale_curve_y);
1636
ClassDB::bind_method(D_METHOD("set_scale_curve_y", "scale_curve"), &CPUParticles3D::set_scale_curve_y);
1637
1638
ClassDB::bind_method(D_METHOD("get_scale_curve_z"), &CPUParticles3D::get_scale_curve_z);
1639
ClassDB::bind_method(D_METHOD("set_scale_curve_z", "scale_curve"), &CPUParticles3D::set_scale_curve_z);
1640
1641
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles3D::convert_from_particles);
1642
1643
ADD_SIGNAL(MethodInfo("finished"));
1644
1645
ADD_GROUP("Emission Shape", "emission_");
1646
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Box,Points,Directed Points,Ring", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape");
1647
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
1648
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
1649
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
1650
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
1651
ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
1652
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_ring_axis"), "set_emission_ring_axis", "get_emission_ring_axis");
1653
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_emission_ring_height", "get_emission_ring_height");
1654
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_emission_ring_radius", "get_emission_ring_radius");
1655
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius");
1656
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_cone_angle", PROPERTY_HINT_RANGE, "0,90,0.01,degrees"), "set_emission_ring_cone_angle", "get_emission_ring_cone_angle");
1657
ADD_GROUP("Particle Flags", "particle_flag_");
1658
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
1659
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y);
1660
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z);
1661
ADD_GROUP("Direction", "");
1662
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction");
1663
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
1664
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness");
1665
ADD_GROUP("Gravity", "");
1666
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
1667
ADD_GROUP("Initial Velocity", "initial_");
1668
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
1669
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
1670
ADD_GROUP("Angular Velocity", "angular_");
1671
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
1672
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
1673
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
1674
ADD_GROUP("Orbit Velocity", "orbit_");
1675
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
1676
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
1677
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
1678
ADD_GROUP("Linear Accel", "linear_");
1679
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
1680
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
1681
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
1682
ADD_GROUP("Radial Accel", "radial_");
1683
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
1684
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
1685
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
1686
ADD_GROUP("Tangential Accel", "tangential_");
1687
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
1688
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
1689
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
1690
ADD_GROUP("Damping", "");
1691
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING);
1692
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING);
1693
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_DAMPING);
1694
ADD_GROUP("Angle", "");
1695
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
1696
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
1697
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_ANGLE);
1698
ADD_GROUP("Scale", "");
1699
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
1700
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE);
1701
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_SCALE);
1702
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "split_scale"), "set_split_scale", "get_split_scale");
1703
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_x", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_scale_curve_x", "get_scale_curve_x");
1704
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_y", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_scale_curve_y", "get_scale_curve_y");
1705
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_z", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_scale_curve_z", "get_scale_curve_z");
1706
ADD_GROUP("Color", "");
1707
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
1708
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, Gradient::get_class_static()), "set_color_ramp", "get_color_ramp");
1709
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_initial_ramp", PROPERTY_HINT_RESOURCE_TYPE, Gradient::get_class_static()), "set_color_initial_ramp", "get_color_initial_ramp");
1710
1711
ADD_GROUP("Hue Variation", "hue_");
1712
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION);
1713
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
1714
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
1715
ADD_GROUP("Animation", "anim_");
1716
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
1717
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
1718
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
1719
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
1720
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
1721
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, Curve::get_class_static()), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
1722
1723
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
1724
BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
1725
BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY);
1726
BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL);
1727
BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL);
1728
BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL);
1729
BIND_ENUM_CONSTANT(PARAM_DAMPING);
1730
BIND_ENUM_CONSTANT(PARAM_ANGLE);
1731
BIND_ENUM_CONSTANT(PARAM_SCALE);
1732
BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION);
1733
BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED);
1734
BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
1735
BIND_ENUM_CONSTANT(PARAM_MAX);
1736
1737
BIND_ENUM_CONSTANT(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
1738
BIND_ENUM_CONSTANT(PARTICLE_FLAG_ROTATE_Y);
1739
BIND_ENUM_CONSTANT(PARTICLE_FLAG_DISABLE_Z);
1740
BIND_ENUM_CONSTANT(PARTICLE_FLAG_MAX);
1741
1742
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
1743
BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
1744
BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE_SURFACE);
1745
BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX);
1746
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
1747
BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
1748
BIND_ENUM_CONSTANT(EMISSION_SHAPE_RING);
1749
BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX);
1750
}
1751
1752
CPUParticles3D::CPUParticles3D() {
1753
set_notify_transform(true);
1754
1755
multimesh = RenderingServer::get_singleton()->multimesh_create();
1756
RenderingServer::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
1757
set_base(multimesh);
1758
1759
set_emitting(true);
1760
set_amount(8);
1761
set_seed(Math::rand());
1762
1763
rng.instantiate();
1764
1765
set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
1766
set_param_min(PARAM_ANGULAR_VELOCITY, 0);
1767
set_param_min(PARAM_ORBIT_VELOCITY, 0);
1768
set_param_min(PARAM_LINEAR_ACCEL, 0);
1769
set_param_min(PARAM_RADIAL_ACCEL, 0);
1770
set_param_min(PARAM_TANGENTIAL_ACCEL, 0);
1771
set_param_min(PARAM_DAMPING, 0);
1772
set_param_min(PARAM_ANGLE, 0);
1773
set_param_min(PARAM_SCALE, 1);
1774
set_param_min(PARAM_HUE_VARIATION, 0);
1775
set_param_min(PARAM_ANIM_SPEED, 0);
1776
set_param_min(PARAM_ANIM_OFFSET, 0);
1777
set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0);
1778
set_param_max(PARAM_ANGULAR_VELOCITY, 0);
1779
set_param_max(PARAM_ORBIT_VELOCITY, 0);
1780
set_param_max(PARAM_LINEAR_ACCEL, 0);
1781
set_param_max(PARAM_RADIAL_ACCEL, 0);
1782
set_param_max(PARAM_TANGENTIAL_ACCEL, 0);
1783
set_param_max(PARAM_DAMPING, 0);
1784
set_param_max(PARAM_ANGLE, 0);
1785
set_param_max(PARAM_SCALE, 1);
1786
set_param_max(PARAM_HUE_VARIATION, 0);
1787
set_param_max(PARAM_ANIM_SPEED, 0);
1788
set_param_max(PARAM_ANIM_OFFSET, 0);
1789
set_emission_shape(EMISSION_SHAPE_POINT);
1790
set_emission_sphere_radius(1);
1791
set_emission_box_extents(Vector3(1, 1, 1));
1792
set_emission_ring_axis(Vector3(0, 0, 1.0));
1793
set_emission_ring_height(1);
1794
set_emission_ring_radius(1);
1795
set_emission_ring_inner_radius(0);
1796
set_emission_ring_cone_angle(90);
1797
1798
set_gravity(Vector3(0, -9.8, 0));
1799
1800
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
1801
particle_flags[i] = false;
1802
}
1803
1804
set_color(Color(1, 1, 1, 1));
1805
}
1806
1807
CPUParticles3D::~CPUParticles3D() {
1808
ERR_FAIL_NULL(RenderingServer::get_singleton());
1809
RS::get_singleton()->free_rid(multimesh);
1810
}
1811
1812