1/**************************************************************************/
2/* particles_storage.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#ifdef GLES3_ENABLED
32
33#include "particles_storage.h"
34#include "material_storage.h"
35#include "mesh_storage.h"
36#include "texture_storage.h"
37#include "utilities.h"
38
39#include "servers/rendering/rendering_server_default.h"
40
41using namespace GLES3;
42
43ParticlesStorage *ParticlesStorage::singleton = nullptr;
44
45ParticlesStorage *ParticlesStorage::get_singleton() {
46 return singleton;
47}
48
49ParticlesStorage::ParticlesStorage() {
50 singleton = this;
51 GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
52
53 {
54 String global_defines;
55 global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
56 material_storage->shaders.particles_process_shader.initialize(global_defines, 1);
57 }
58 {
59 // default material and shader for particles shader
60 particles_shader.default_shader = material_storage->shader_allocate();
61 material_storage->shader_initialize(particles_shader.default_shader);
62 material_storage->shader_set_code(particles_shader.default_shader, R"(
63// Default particles shader.
64
65shader_type particles;
66
67void process() {
68 COLOR = vec4(1.0);
69}
70)");
71 particles_shader.default_material = material_storage->material_allocate();
72 material_storage->material_initialize(particles_shader.default_material);
73 material_storage->material_set_shader(particles_shader.default_material, particles_shader.default_shader);
74 }
75 {
76 particles_shader.copy_shader.initialize();
77 particles_shader.copy_shader_version = particles_shader.copy_shader.version_create();
78 }
79}
80
81ParticlesStorage::~ParticlesStorage() {
82 singleton = nullptr;
83 GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
84
85 material_storage->material_free(particles_shader.default_material);
86 material_storage->shader_free(particles_shader.default_shader);
87 particles_shader.copy_shader.version_free(particles_shader.copy_shader_version);
88}
89
90/* PARTICLES */
91
92RID ParticlesStorage::particles_allocate() {
93 return particles_owner.allocate_rid();
94}
95
96void ParticlesStorage::particles_initialize(RID p_rid) {
97 particles_owner.initialize_rid(p_rid, Particles());
98}
99
100void ParticlesStorage::particles_free(RID p_rid) {
101 update_particles();
102 Particles *particles = particles_owner.get_or_null(p_rid);
103 particles->dependency.deleted_notify(p_rid);
104 _particles_free_data(particles);
105 particles_owner.free(p_rid);
106}
107
108void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
109 Particles *particles = particles_owner.get_or_null(p_particles);
110 ERR_FAIL_NULL(particles);
111 if (particles->mode == p_mode) {
112 return;
113 }
114
115 _particles_free_data(particles);
116
117 particles->mode = p_mode;
118}
119
120void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) {
121 Particles *particles = particles_owner.get_or_null(p_particles);
122 ERR_FAIL_NULL(particles);
123
124 particles->emitting = p_emitting;
125}
126
127bool ParticlesStorage::particles_get_emitting(RID p_particles) {
128 ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
129 Particles *particles = particles_owner.get_or_null(p_particles);
130 ERR_FAIL_NULL_V(particles, false);
131
132 return particles->emitting;
133}
134
135void ParticlesStorage::_particles_free_data(Particles *particles) {
136 particles->userdata_count = 0;
137 particles->instance_buffer_size_cache = 0;
138 particles->instance_buffer_stride_cache = 0;
139 particles->num_attrib_arrays_cache = 0;
140 particles->process_buffer_stride_cache = 0;
141
142 if (particles->front_process_buffer != 0) {
143 glDeleteVertexArrays(1, &particles->front_vertex_array);
144 GLES3::Utilities::get_singleton()->buffer_free_data(particles->front_process_buffer);
145 GLES3::Utilities::get_singleton()->buffer_free_data(particles->front_instance_buffer);
146 particles->front_vertex_array = 0;
147 particles->front_process_buffer = 0;
148 particles->front_instance_buffer = 0;
149
150 glDeleteVertexArrays(1, &particles->back_vertex_array);
151 GLES3::Utilities::get_singleton()->buffer_free_data(particles->back_process_buffer);
152 GLES3::Utilities::get_singleton()->buffer_free_data(particles->back_instance_buffer);
153 particles->back_vertex_array = 0;
154 particles->back_process_buffer = 0;
155 particles->back_instance_buffer = 0;
156 }
157
158 if (particles->sort_buffer != 0) {
159 GLES3::Utilities::get_singleton()->buffer_free_data(particles->last_frame_buffer);
160 GLES3::Utilities::get_singleton()->buffer_free_data(particles->sort_buffer);
161 particles->last_frame_buffer = 0;
162 particles->sort_buffer = 0;
163 particles->sort_buffer_filled = false;
164 particles->last_frame_buffer_filled = false;
165 }
166
167 if (particles->frame_params_ubo != 0) {
168 GLES3::Utilities::get_singleton()->buffer_free_data(particles->frame_params_ubo);
169 particles->frame_params_ubo = 0;
170 }
171}
172
173void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
174 Particles *particles = particles_owner.get_or_null(p_particles);
175 ERR_FAIL_NULL(particles);
176
177 if (particles->amount == p_amount) {
178 return;
179 }
180
181 _particles_free_data(particles);
182
183 particles->amount = p_amount;
184
185 particles->prev_ticks = 0;
186 particles->phase = 0;
187 particles->prev_phase = 0;
188 particles->clear = true;
189
190 particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
191}
192
193void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {
194 Particles *particles = particles_owner.get_or_null(p_particles);
195 ERR_FAIL_NULL(particles);
196 particles->lifetime = p_lifetime;
197}
198
199void ParticlesStorage::particles_set_one_shot(RID p_particles, bool p_one_shot) {
200 Particles *particles = particles_owner.get_or_null(p_particles);
201 ERR_FAIL_NULL(particles);
202 particles->one_shot = p_one_shot;
203}
204
205void ParticlesStorage::particles_set_pre_process_time(RID p_particles, double p_time) {
206 Particles *particles = particles_owner.get_or_null(p_particles);
207 ERR_FAIL_NULL(particles);
208 particles->pre_process_time = p_time;
209}
210void ParticlesStorage::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) {
211 Particles *particles = particles_owner.get_or_null(p_particles);
212 ERR_FAIL_NULL(particles);
213 particles->explosiveness = p_ratio;
214}
215void ParticlesStorage::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) {
216 Particles *particles = particles_owner.get_or_null(p_particles);
217 ERR_FAIL_NULL(particles);
218 particles->randomness = p_ratio;
219}
220
221void ParticlesStorage::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
222 Particles *particles = particles_owner.get_or_null(p_particles);
223 ERR_FAIL_NULL(particles);
224 particles->custom_aabb = p_aabb;
225 particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
226}
227
228void ParticlesStorage::particles_set_speed_scale(RID p_particles, double p_scale) {
229 Particles *particles = particles_owner.get_or_null(p_particles);
230 ERR_FAIL_NULL(particles);
231
232 particles->speed_scale = p_scale;
233}
234void ParticlesStorage::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
235 Particles *particles = particles_owner.get_or_null(p_particles);
236 ERR_FAIL_NULL(particles);
237
238 particles->use_local_coords = p_enable;
239 particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
240}
241
242void ParticlesStorage::particles_set_fixed_fps(RID p_particles, int p_fps) {
243 Particles *particles = particles_owner.get_or_null(p_particles);
244 ERR_FAIL_NULL(particles);
245
246 particles->fixed_fps = p_fps;
247
248 _particles_free_data(particles);
249
250 particles->prev_ticks = 0;
251 particles->phase = 0;
252 particles->prev_phase = 0;
253 particles->clear = true;
254
255 particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
256}
257
258void ParticlesStorage::particles_set_interpolate(RID p_particles, bool p_enable) {
259 Particles *particles = particles_owner.get_or_null(p_particles);
260 ERR_FAIL_NULL(particles);
261
262 particles->interpolate = p_enable;
263}
264
265void ParticlesStorage::particles_set_fractional_delta(RID p_particles, bool p_enable) {
266 Particles *particles = particles_owner.get_or_null(p_particles);
267 ERR_FAIL_NULL(particles);
268
269 particles->fractional_delta = p_enable;
270}
271
272void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, double p_length) {
273 if (p_enable) {
274 WARN_PRINT_ONCE_ED("The GL Compatibility rendering backend does not support particle trails.");
275 }
276}
277
278void ParticlesStorage::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {
279 if (p_bind_poses.size() != 0) {
280 WARN_PRINT_ONCE_ED("The GL Compatibility rendering backend does not support particle trails.");
281 }
282}
283
284void ParticlesStorage::particles_set_collision_base_size(RID p_particles, real_t p_size) {
285 Particles *particles = particles_owner.get_or_null(p_particles);
286 ERR_FAIL_NULL(particles);
287
288 particles->collision_base_size = p_size;
289}
290
291void ParticlesStorage::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
292 Particles *particles = particles_owner.get_or_null(p_particles);
293 ERR_FAIL_NULL(particles);
294
295 particles->transform_align = p_transform_align;
296}
297
298void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) {
299 Particles *particles = particles_owner.get_or_null(p_particles);
300 ERR_FAIL_NULL(particles);
301
302 particles->process_material = p_material;
303 particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES); //the instance buffer may have changed
304}
305
306RID ParticlesStorage::particles_get_process_material(RID p_particles) const {
307 Particles *particles = particles_owner.get_or_null(p_particles);
308 ERR_FAIL_NULL_V(particles, RID());
309
310 return particles->process_material;
311}
312
313void ParticlesStorage::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
314 Particles *particles = particles_owner.get_or_null(p_particles);
315 ERR_FAIL_NULL(particles);
316
317 particles->draw_order = p_order;
318}
319
320void ParticlesStorage::particles_set_draw_passes(RID p_particles, int p_passes) {
321 Particles *particles = particles_owner.get_or_null(p_particles);
322 ERR_FAIL_NULL(particles);
323
324 particles->draw_passes.resize(p_passes);
325}
326
327void ParticlesStorage::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
328 Particles *particles = particles_owner.get_or_null(p_particles);
329 ERR_FAIL_NULL(particles);
330 ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
331 particles->draw_passes.write[p_pass] = p_mesh;
332 particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
333}
334
335void ParticlesStorage::particles_restart(RID p_particles) {
336 Particles *particles = particles_owner.get_or_null(p_particles);
337 ERR_FAIL_NULL(particles);
338
339 particles->restart_request = true;
340}
341
342void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
343 if (p_subemitter_particles.is_valid()) {
344 WARN_PRINT_ONCE_ED("The GL Compatibility rendering backend does not support particle sub-emitters.");
345 }
346}
347
348void ParticlesStorage::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
349 WARN_PRINT_ONCE_ED("The GL Compatibility rendering backend does not support manually emitting particles.");
350}
351
352void ParticlesStorage::particles_request_process(RID p_particles) {
353 Particles *particles = particles_owner.get_or_null(p_particles);
354 ERR_FAIL_NULL(particles);
355
356 if (!particles->dirty) {
357 particles->dirty = true;
358 particles->update_list = particle_update_list;
359 particle_update_list = particles;
360 }
361}
362
363AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) {
364 if (RSG::threaded) {
365 WARN_PRINT_ONCE("Calling this function with threaded rendering enabled stalls the renderer, use with care.");
366 }
367
368 const Particles *particles = particles_owner.get_or_null(p_particles);
369 ERR_FAIL_NULL_V(particles, AABB());
370
371 int total_amount = particles->amount;
372
373 // If available, read from the sort buffer which should be 2 frames out of date.
374 // This will help alleviate GPU stalls.
375 GLuint read_buffer = particles->sort_buffer_filled ? particles->sort_buffer : particles->back_instance_buffer;
376
377 Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, read_buffer, total_amount * sizeof(ParticleInstanceData3D));
378 ERR_FAIL_COND_V(buffer.size() != (int)(total_amount * sizeof(ParticleInstanceData3D)), AABB());
379
380 Transform3D inv = particles->emission_transform.affine_inverse();
381
382 AABB aabb;
383 if (buffer.size()) {
384 bool first = true;
385
386 const uint8_t *data_ptr = (const uint8_t *)buffer.ptr();
387 uint32_t particle_data_size = sizeof(ParticleInstanceData3D) + sizeof(float) * particles->userdata_count;
388
389 for (int i = 0; i < total_amount; i++) {
390 const ParticleInstanceData3D &particle_data = *(const ParticleInstanceData3D *)&data_ptr[particle_data_size * i];
391 // If scale is 0.0, we assume the particle is inactive.
392 if (particle_data.xform[0] > 0.0) {
393 Vector3 pos = Vector3(particle_data.xform[3], particle_data.xform[7], particle_data.xform[11]);
394 if (!particles->use_local_coords) {
395 pos = inv.xform(pos);
396 }
397 if (first) {
398 aabb.position = pos;
399 first = false;
400 } else {
401 aabb.expand_to(pos);
402 }
403 }
404 }
405 }
406
407 float longest_axis_size = 0;
408 for (int i = 0; i < particles->draw_passes.size(); i++) {
409 if (particles->draw_passes[i].is_valid()) {
410 AABB maabb = MeshStorage::get_singleton()->mesh_get_aabb(particles->draw_passes[i], RID());
411 longest_axis_size = MAX(maabb.get_longest_axis_size(), longest_axis_size);
412 }
413 }
414
415 aabb.grow_by(longest_axis_size);
416
417 return aabb;
418}
419
420AABB ParticlesStorage::particles_get_aabb(RID p_particles) const {
421 const Particles *particles = particles_owner.get_or_null(p_particles);
422 ERR_FAIL_NULL_V(particles, AABB());
423
424 return particles->custom_aabb;
425}
426
427void ParticlesStorage::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {
428 Particles *particles = particles_owner.get_or_null(p_particles);
429 ERR_FAIL_NULL(particles);
430
431 particles->emission_transform = p_transform;
432}
433
434int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {
435 const Particles *particles = particles_owner.get_or_null(p_particles);
436 ERR_FAIL_NULL_V(particles, 0);
437
438 return particles->draw_passes.size();
439}
440
441RID ParticlesStorage::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
442 const Particles *particles = particles_owner.get_or_null(p_particles);
443 ERR_FAIL_NULL_V(particles, RID());
444 ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID());
445
446 return particles->draw_passes[p_pass];
447}
448
449void ParticlesStorage::particles_add_collision(RID p_particles, RID p_particles_collision_instance) {
450 Particles *particles = particles_owner.get_or_null(p_particles);
451 ERR_FAIL_NULL(particles);
452 particles->collisions.insert(p_particles_collision_instance);
453}
454
455void ParticlesStorage::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) {
456 Particles *particles = particles_owner.get_or_null(p_particles);
457 ERR_FAIL_NULL(particles);
458 particles->collisions.erase(p_particles_collision_instance);
459}
460
461void ParticlesStorage::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, GLuint p_texture) {
462 Particles *particles = particles_owner.get_or_null(p_particles);
463 ERR_FAIL_NULL(particles);
464 particles->has_sdf_collision = p_enable;
465 particles->sdf_collision_transform = p_xform;
466 particles->sdf_collision_to_screen = p_to_screen;
467 particles->sdf_collision_texture = p_texture;
468}
469
470// Does one step of processing particles by reading from back_process_buffer and writing to front_process_buffer.
471void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta) {
472 GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
473 GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
474
475 double new_phase = Math::fmod(p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, 1.0);
476
477 //update current frame
478 ParticlesFrameParams frame_params;
479
480 if (p_particles->clear) {
481 p_particles->cycle_number = 0;
482 p_particles->random_seed = Math::rand();
483 } else if (new_phase < p_particles->phase) {
484 if (p_particles->one_shot) {
485 p_particles->emitting = false;
486 }
487 p_particles->cycle_number++;
488 }
489
490 frame_params.emitting = p_particles->emitting;
491 frame_params.system_phase = new_phase;
492 frame_params.prev_system_phase = p_particles->phase;
493
494 p_particles->phase = new_phase;
495
496 frame_params.time = RSG::rasterizer->get_total_time();
497 frame_params.delta = p_delta * p_particles->speed_scale;
498 frame_params.random_seed = p_particles->random_seed;
499 frame_params.explosiveness = p_particles->explosiveness;
500 frame_params.randomness = p_particles->randomness;
501
502 if (p_particles->use_local_coords) {
503 GLES3::MaterialStorage::store_transform(Transform3D(), frame_params.emission_transform);
504 } else {
505 GLES3::MaterialStorage::store_transform(p_particles->emission_transform, frame_params.emission_transform);
506 }
507
508 frame_params.cycle = p_particles->cycle_number;
509 frame_params.frame = p_particles->frame_counter++;
510 frame_params.pad0 = 0;
511 frame_params.pad1 = 0;
512 frame_params.pad2 = 0;
513
514 { //collision and attractors
515
516 frame_params.collider_count = 0;
517 frame_params.attractor_count = 0;
518 frame_params.particle_size = p_particles->collision_base_size;
519
520 GLuint collision_heightmap_texture = 0;
521
522 Transform3D to_particles;
523 if (p_particles->use_local_coords) {
524 to_particles = p_particles->emission_transform.affine_inverse();
525 }
526
527 if (p_particles->has_sdf_collision && p_particles->sdf_collision_texture != 0) {
528 //2D collision
529
530 Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand
531
532 if (!p_particles->use_local_coords) {
533 Transform2D emission;
534 emission.columns[0] = Vector2(p_particles->emission_transform.basis.get_column(0).x, p_particles->emission_transform.basis.get_column(0).y);
535 emission.columns[1] = Vector2(p_particles->emission_transform.basis.get_column(1).x, p_particles->emission_transform.basis.get_column(1).y);
536 emission.set_origin(Vector2(p_particles->emission_transform.origin.x, p_particles->emission_transform.origin.y));
537 xform = xform * emission.affine_inverse();
538 }
539
540 Transform2D revert = xform.affine_inverse();
541 frame_params.collider_count = 1;
542 frame_params.colliders[0].transform[0] = xform.columns[0][0];
543 frame_params.colliders[0].transform[1] = xform.columns[0][1];
544 frame_params.colliders[0].transform[2] = 0;
545 frame_params.colliders[0].transform[3] = xform.columns[2][0];
546
547 frame_params.colliders[0].transform[4] = xform.columns[1][0];
548 frame_params.colliders[0].transform[5] = xform.columns[1][1];
549 frame_params.colliders[0].transform[6] = 0;
550 frame_params.colliders[0].transform[7] = xform.columns[2][1];
551
552 frame_params.colliders[0].transform[8] = revert.columns[0][0];
553 frame_params.colliders[0].transform[9] = revert.columns[0][1];
554 frame_params.colliders[0].transform[10] = 0;
555 frame_params.colliders[0].transform[11] = revert.columns[2][0];
556
557 frame_params.colliders[0].transform[12] = revert.columns[1][0];
558 frame_params.colliders[0].transform[13] = revert.columns[1][1];
559 frame_params.colliders[0].transform[14] = 0;
560 frame_params.colliders[0].transform[15] = revert.columns[2][1];
561
562 frame_params.colliders[0].extents[0] = p_particles->sdf_collision_to_screen.size.x;
563 frame_params.colliders[0].extents[1] = p_particles->sdf_collision_to_screen.size.y;
564 frame_params.colliders[0].extents[2] = p_particles->sdf_collision_to_screen.position.x;
565 frame_params.colliders[0].scale = p_particles->sdf_collision_to_screen.position.y;
566 frame_params.colliders[0].type = ParticlesFrameParams::COLLISION_TYPE_2D_SDF;
567
568 collision_heightmap_texture = p_particles->sdf_collision_texture;
569 }
570
571 for (const RID &E : p_particles->collisions) {
572 ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(E);
573 if (!pci || !pci->active) {
574 continue;
575 }
576 ParticlesCollision *pc = particles_collision_owner.get_or_null(pci->collision);
577 ERR_CONTINUE(!pc);
578
579 Transform3D to_collider = pci->transform;
580 if (p_particles->use_local_coords) {
581 to_collider = to_particles * to_collider;
582 }
583 Vector3 scale = to_collider.basis.get_scale();
584 to_collider.basis.orthonormalize();
585
586 if (pc->type <= RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT) {
587 //attractor
588 if (frame_params.attractor_count >= ParticlesFrameParams::MAX_ATTRACTORS) {
589 continue;
590 }
591
592 ParticlesFrameParams::Attractor &attr = frame_params.attractors[frame_params.attractor_count];
593
594 GLES3::MaterialStorage::store_transform(to_collider, attr.transform);
595 attr.strength = pc->attractor_strength;
596 attr.attenuation = pc->attractor_attenuation;
597 attr.directionality = pc->attractor_directionality;
598
599 switch (pc->type) {
600 case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT: {
601 attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_SPHERE;
602 float radius = pc->radius;
603 radius *= (scale.x + scale.y + scale.z) / 3.0;
604 attr.extents[0] = radius;
605 attr.extents[1] = radius;
606 attr.extents[2] = radius;
607 } break;
608 case RS::PARTICLES_COLLISION_TYPE_BOX_ATTRACT: {
609 attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_BOX;
610 Vector3 extents = pc->extents * scale;
611 attr.extents[0] = extents.x;
612 attr.extents[1] = extents.y;
613 attr.extents[2] = extents.z;
614 } break;
615 case RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT: {
616 WARN_PRINT_ONCE_ED("Vector field particle attractors are not available in the GL Compatibility rendering backend.");
617 } break;
618 default: {
619 }
620 }
621
622 frame_params.attractor_count++;
623 } else {
624 //collider
625 if (frame_params.collider_count >= ParticlesFrameParams::MAX_COLLIDERS) {
626 continue;
627 }
628
629 ParticlesFrameParams::Collider &col = frame_params.colliders[frame_params.collider_count];
630
631 GLES3::MaterialStorage::store_transform(to_collider, col.transform);
632 switch (pc->type) {
633 case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: {
634 col.type = ParticlesFrameParams::COLLISION_TYPE_SPHERE;
635 float radius = pc->radius;
636 radius *= (scale.x + scale.y + scale.z) / 3.0;
637 col.extents[0] = radius;
638 col.extents[1] = radius;
639 col.extents[2] = radius;
640 } break;
641 case RS::PARTICLES_COLLISION_TYPE_BOX_COLLIDE: {
642 col.type = ParticlesFrameParams::COLLISION_TYPE_BOX;
643 Vector3 extents = pc->extents * scale;
644 col.extents[0] = extents.x;
645 col.extents[1] = extents.y;
646 col.extents[2] = extents.z;
647 } break;
648 case RS::PARTICLES_COLLISION_TYPE_SDF_COLLIDE: {
649 WARN_PRINT_ONCE_ED("SDF Particle Colliders are not available in the GL Compatibility rendering backend.");
650 } break;
651 case RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE: {
652 if (collision_heightmap_texture != 0) { //already taken
653 continue;
654 }
655
656 col.type = ParticlesFrameParams::COLLISION_TYPE_HEIGHT_FIELD;
657 Vector3 extents = pc->extents * scale;
658 col.extents[0] = extents.x;
659 col.extents[1] = extents.y;
660 col.extents[2] = extents.z;
661 collision_heightmap_texture = pc->heightfield_texture;
662 } break;
663 default: {
664 }
665 }
666
667 frame_params.collider_count++;
668 }
669 }
670
671 // Bind heightmap or SDF texture.
672 GLuint heightmap = collision_heightmap_texture;
673 if (heightmap == 0) {
674 GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_BLACK));
675 heightmap = tex->tex_id;
676 }
677 glActiveTexture(GL_TEXTURE0);
678 glBindTexture(GL_TEXTURE_2D, heightmap);
679 }
680
681 if (p_particles->frame_params_ubo == 0) {
682 glGenBuffers(1, &p_particles->frame_params_ubo);
683 glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
684 GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, p_particles->frame_params_ubo, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW, "Particle Frame UBO");
685 } else {
686 // Update per-frame UBO.
687 glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
688 glBufferData(GL_UNIFORM_BUFFER, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW);
689 }
690
691 // Get shader and set shader uniforms;
692 ParticleProcessMaterialData *m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(p_particles->process_material, RS::SHADER_PARTICLES));
693 if (!m) {
694 m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, RS::SHADER_PARTICLES));
695 }
696
697 ERR_FAIL_NULL(m);
698
699 ParticlesShaderGLES3::ShaderVariant variant = ParticlesShaderGLES3::MODE_DEFAULT;
700
701 uint32_t specialization = 0;
702 for (uint32_t i = 0; i < p_particles->userdata_count; i++) {
703 specialization |= (1 << i);
704 }
705
706 if (p_particles->mode == RS::ParticlesMode::PARTICLES_MODE_3D) {
707 specialization |= ParticlesShaderGLES3::MODE_3D;
708 }
709
710 RID version = particles_shader.default_shader_version;
711 if (m->shader_data->version.is_valid() && m->shader_data->valid) {
712 // Bind material uniform buffer and textures.
713 m->bind_uniforms();
714 version = m->shader_data->version;
715 }
716
717 bool success = material_storage->shaders.particles_process_shader.version_bind_shader(version, variant, specialization);
718 if (!success) {
719 return;
720 }
721
722 material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::LIFETIME, p_particles->lifetime, version, variant, specialization);
723 material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::CLEAR, p_particles->clear, version, variant, specialization);
724 material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::TOTAL_PARTICLES, uint32_t(p_particles->amount), version, variant, specialization);
725 material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::USE_FRACTIONAL_DELTA, p_particles->fractional_delta, version, variant, specialization);
726
727 p_particles->clear = false;
728
729 p_particles->has_collision_cache = m->shader_data->uses_collision;
730
731 glBindVertexArray(p_particles->back_vertex_array);
732
733 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, p_particles->front_process_buffer);
734
735 glBeginTransformFeedback(GL_POINTS);
736 glDrawArrays(GL_POINTS, 0, p_particles->amount);
737 glEndTransformFeedback();
738
739 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
740 glBindVertexArray(0);
741
742 SWAP(p_particles->front_process_buffer, p_particles->back_process_buffer);
743 SWAP(p_particles->front_vertex_array, p_particles->back_vertex_array);
744}
745
746void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
747 Particles *particles = particles_owner.get_or_null(p_particles);
748 ERR_FAIL_NULL(particles);
749
750 if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
751 return;
752 }
753
754 if (particles->front_process_buffer == 0) {
755 return; //particles have not processed yet
756 }
757
758 Vector3 axis = -p_axis; // cameras look to z negative
759
760 if (particles->use_local_coords) {
761 axis = particles->emission_transform.basis.xform_inv(axis).normalized();
762 }
763
764 // Sort will be done on CPU since we don't have compute shaders.
765 // If the sort_buffer has valid data
766 // Use a buffer that is 2 frames out of date to avoid stalls.
767 if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->sort_buffer_filled) {
768 glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);
769
770 ParticleInstanceData3D *particle_array;
771#ifndef __EMSCRIPTEN__
772 particle_array = static_cast<ParticleInstanceData3D *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
773 ERR_FAIL_NULL(particle_array);
774#else
775 LocalVector<ParticleInstanceData3D> particle_vector;
776 particle_vector.resize(particles->amount);
777 particle_array = particle_vector.ptr();
778 glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), particle_array);
779#endif
780 SortArray<ParticleInstanceData3D, ParticlesViewSort> sorter;
781 sorter.compare.z_dir = axis;
782 sorter.sort(particle_array, particles->amount);
783
784#ifndef __EMSCRIPTEN__
785 glUnmapBuffer(GL_ARRAY_BUFFER);
786#else
787 glBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), particle_vector.ptr());
788#endif
789 }
790
791 glEnable(GL_RASTERIZER_DISCARD);
792 _particles_update_instance_buffer(particles, axis, p_up_axis);
793 glDisable(GL_RASTERIZER_DISCARD);
794}
795
796void ParticlesStorage::_particles_update_buffers(Particles *particles) {
797 GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
798 uint32_t userdata_count = 0;
799
800 if (particles->process_material.is_valid()) {
801 GLES3::ParticleProcessMaterialData *material_data = static_cast<GLES3::ParticleProcessMaterialData *>(material_storage->material_get_data(particles->process_material, RS::SHADER_PARTICLES));
802 if (material_data && material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
803 userdata_count = material_data->shader_data->userdata_count;
804 }
805 }
806
807 if (userdata_count != particles->userdata_count) {
808 // Mismatch userdata, re-create buffers.
809 _particles_free_data(particles);
810 }
811
812 if (particles->amount > 0 && particles->front_process_buffer == 0) {
813 int total_amount = particles->amount;
814
815 particles->userdata_count = userdata_count;
816
817 uint32_t xform_size = particles->mode == RS::PARTICLES_MODE_2D ? 2 : 3;
818 particles->instance_buffer_stride_cache = sizeof(float) * 4 * (xform_size + 1);
819 particles->instance_buffer_size_cache = particles->instance_buffer_stride_cache * total_amount;
820 particles->num_attrib_arrays_cache = 5 + userdata_count + (xform_size - 2);
821 particles->process_buffer_stride_cache = sizeof(float) * 4 * particles->num_attrib_arrays_cache;
822
823 PackedByteArray data;
824 data.resize_zeroed(particles->process_buffer_stride_cache * total_amount);
825
826 PackedByteArray instance_data;
827 instance_data.resize_zeroed(particles->instance_buffer_size_cache);
828
829 {
830 glGenVertexArrays(1, &particles->front_vertex_array);
831 glBindVertexArray(particles->front_vertex_array);
832 glGenBuffers(1, &particles->front_process_buffer);
833 glGenBuffers(1, &particles->front_instance_buffer);
834
835 glBindBuffer(GL_ARRAY_BUFFER, particles->front_process_buffer);
836 GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_process_buffer, particles->process_buffer_stride_cache * total_amount, data.ptr(), GL_DYNAMIC_COPY, "Particles front process buffer");
837
838 for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
839 glEnableVertexAttribArray(j);
840 glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, particles->process_buffer_stride_cache, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));
841 }
842 glBindVertexArray(0);
843
844 glBindBuffer(GL_ARRAY_BUFFER, particles->front_instance_buffer);
845 GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->front_instance_buffer, particles->instance_buffer_size_cache, instance_data.ptr(), GL_DYNAMIC_COPY, "Particles front instance buffer");
846 }
847
848 {
849 glGenVertexArrays(1, &particles->back_vertex_array);
850 glBindVertexArray(particles->back_vertex_array);
851 glGenBuffers(1, &particles->back_process_buffer);
852 glGenBuffers(1, &particles->back_instance_buffer);
853
854 glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
855 GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_process_buffer, particles->process_buffer_stride_cache * total_amount, data.ptr(), GL_DYNAMIC_COPY, "Particles back process buffer");
856
857 for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
858 glEnableVertexAttribArray(j);
859 glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, particles->process_buffer_stride_cache, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));
860 }
861 glBindVertexArray(0);
862
863 glBindBuffer(GL_ARRAY_BUFFER, particles->back_instance_buffer);
864 GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->back_instance_buffer, particles->instance_buffer_size_cache, instance_data.ptr(), GL_DYNAMIC_COPY, "Particles back instance buffer");
865 }
866 glBindBuffer(GL_ARRAY_BUFFER, 0);
867 }
868}
869
870void ParticlesStorage::_particles_allocate_history_buffers(Particles *particles) {
871 if (particles->sort_buffer == 0) {
872 glGenBuffers(1, &particles->last_frame_buffer);
873 glBindBuffer(GL_ARRAY_BUFFER, particles->last_frame_buffer);
874 GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->last_frame_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ, "Particles last frame buffer");
875
876 glGenBuffers(1, &particles->sort_buffer);
877 glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);
878 GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->sort_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ, "Particles sort buffer");
879
880 particles->sort_buffer_filled = false;
881 particles->last_frame_buffer_filled = false;
882 glBindBuffer(GL_ARRAY_BUFFER, 0);
883 }
884}
885void ParticlesStorage::_particles_update_instance_buffer(Particles *particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
886 ParticlesCopyShaderGLES3::ShaderVariant variant = ParticlesCopyShaderGLES3::MODE_DEFAULT;
887
888 uint64_t specialization = 0;
889 if (particles->mode == RS::ParticlesMode::PARTICLES_MODE_3D) {
890 specialization |= ParticlesCopyShaderGLES3::MODE_3D;
891 }
892
893 bool success = particles_shader.copy_shader.version_bind_shader(particles_shader.copy_shader_version, variant, specialization);
894 if (!success) {
895 return;
896 }
897
898 // Affect 2D only.
899 if (particles->use_local_coords) {
900 // In local mode, particle positions are calculated locally (relative to the node position)
901 // and they're also drawn locally.
902 // It works as expected, so we just pass an identity transform.
903 particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::INV_EMISSION_TRANSFORM, Transform3D(), particles_shader.copy_shader_version, variant, specialization);
904 } else {
905 // In global mode, particle positions are calculated globally (relative to the canvas origin)
906 // but they're drawn locally.
907 // So, we need to pass the inverse of the emission transform to bring the
908 // particles to local coordinates before drawing.
909 Transform3D inv = particles->emission_transform.affine_inverse();
910 particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::INV_EMISSION_TRANSFORM, inv, particles_shader.copy_shader_version, variant, specialization);
911 }
912
913 particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::FRAME_REMAINDER, particles->interpolate ? particles->frame_remainder : 0.0, particles_shader.copy_shader_version, variant, specialization);
914 particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::ALIGN_MODE, uint32_t(particles->transform_align), particles_shader.copy_shader_version, variant, specialization);
915 particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::ALIGN_UP, p_up_axis, particles_shader.copy_shader_version, variant, specialization);
916 particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::SORT_DIRECTION, p_axis, particles_shader.copy_shader_version, variant, specialization);
917
918 glBindVertexArray(particles->back_vertex_array);
919 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->front_instance_buffer, 0, particles->instance_buffer_size_cache);
920 glBeginTransformFeedback(GL_POINTS);
921
922 if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME) {
923 uint32_t lifetime_split = (MIN(int(particles->amount * particles->phase), particles->amount - 1) + 1) % particles->amount;
924 uint32_t stride = particles->process_buffer_stride_cache;
925
926 glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
927
928 // Offset VBO so you render starting at the newest particle.
929 if (particles->amount - lifetime_split > 0) {
930 glEnableVertexAttribArray(0); // Color.
931 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 0));
932 glEnableVertexAttribArray(1); // .xyz: velocity. .z: flags.
933 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 1));
934 glEnableVertexAttribArray(2); // Custom.
935 glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 2));
936 glEnableVertexAttribArray(3); // Xform1.
937 glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 3));
938 glEnableVertexAttribArray(4); // Xform2.
939 glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 4));
940 if (particles->mode == RS::PARTICLES_MODE_3D) {
941 glEnableVertexAttribArray(5); // Xform3.
942 glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 5));
943 }
944
945 uint32_t to_draw = particles->amount - lifetime_split;
946 glDrawArrays(GL_POINTS, 0, to_draw);
947 }
948
949 // Then render from index 0 up intil the newest particle.
950 if (lifetime_split > 0) {
951 glEndTransformFeedback();
952 // Now output to the second portion of the instance buffer.
953 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->front_instance_buffer, particles->instance_buffer_stride_cache * (particles->amount - lifetime_split), particles->instance_buffer_stride_cache * (lifetime_split));
954 glBeginTransformFeedback(GL_POINTS);
955 // Reset back to normal.
956 for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
957 glEnableVertexAttribArray(j);
958 glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));
959 }
960
961 glDrawArrays(GL_POINTS, 0, lifetime_split);
962 }
963 } else {
964 glDrawArrays(GL_POINTS, 0, particles->amount);
965 }
966
967 glEndTransformFeedback();
968 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, 0, 0);
969 glBindVertexArray(0);
970 glBindBuffer(GL_ARRAY_BUFFER, 0);
971}
972
973void ParticlesStorage::update_particles() {
974 glEnable(GL_RASTERIZER_DISCARD);
975
976 GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer();
977
978 glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_GLOBALS_UNIFORM_LOCATION, global_buffer);
979 glBindBuffer(GL_UNIFORM_BUFFER, 0);
980
981 while (particle_update_list) {
982 // Use transform feedback to process particles.
983
984 Particles *particles = particle_update_list;
985
986 particle_update_list = particles->update_list;
987 particles->update_list = nullptr;
988 particles->dirty = false;
989
990 _particles_update_buffers(particles);
991
992 if (particles->restart_request) {
993 particles->prev_ticks = 0;
994 particles->phase = 0;
995 particles->prev_phase = 0;
996 particles->clear = true;
997 particles->restart_request = false;
998 }
999
1000 if (particles->inactive && !particles->emitting) {
1001 //go next
1002 continue;
1003 }
1004
1005 if (particles->emitting) {
1006 if (particles->inactive) {
1007 //restart system from scratch
1008 particles->prev_ticks = 0;
1009 particles->phase = 0;
1010 particles->prev_phase = 0;
1011 particles->clear = true;
1012 }
1013 particles->inactive = false;
1014 particles->inactive_time = 0;
1015 } else {
1016 particles->inactive_time += particles->speed_scale * RSG::rasterizer->get_frame_delta_time();
1017 if (particles->inactive_time > particles->lifetime * 1.2) {
1018 particles->inactive = true;
1019 continue;
1020 }
1021 }
1022
1023 // Copy the instance buffer that was last used into the last_frame buffer.
1024 // sort_buffer should now be 2 frames out of date.
1025 if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME) {
1026 _particles_allocate_history_buffers(particles);
1027 SWAP(particles->last_frame_buffer, particles->sort_buffer);
1028
1029 glBindBuffer(GL_COPY_READ_BUFFER, particles->back_instance_buffer);
1030 glBindBuffer(GL_COPY_WRITE_BUFFER, particles->last_frame_buffer);
1031 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, particles->instance_buffer_size_cache);
1032
1033 // Last frame's last_frame turned into this frame's sort buffer.
1034 particles->sort_buffer_filled = particles->last_frame_buffer_filled;
1035 particles->sort_buffer_phase = particles->last_frame_phase;
1036 particles->last_frame_buffer_filled = true;
1037 particles->last_frame_phase = particles->phase;
1038 glBindBuffer(GL_COPY_READ_BUFFER, 0);
1039 glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
1040 }
1041
1042 int fixed_fps = 0;
1043 if (particles->fixed_fps > 0) {
1044 fixed_fps = particles->fixed_fps;
1045 }
1046
1047 bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
1048
1049 if (particles->clear && particles->pre_process_time > 0.0) {
1050 double frame_time;
1051 if (fixed_fps > 0) {
1052 frame_time = 1.0 / fixed_fps;
1053 } else {
1054 frame_time = 1.0 / 30.0;
1055 }
1056
1057 double todo = particles->pre_process_time;
1058
1059 while (todo >= 0) {
1060 _particles_process(particles, frame_time);
1061 todo -= frame_time;
1062 }
1063 }
1064
1065 if (fixed_fps > 0) {
1066 double frame_time;
1067 double decr;
1068 if (zero_time_scale) {
1069 frame_time = 0.0;
1070 decr = 1.0 / fixed_fps;
1071 } else {
1072 frame_time = 1.0 / fixed_fps;
1073 decr = frame_time;
1074 }
1075 double delta = RSG::rasterizer->get_frame_delta_time();
1076 if (delta > 0.1) { //avoid recursive stalls if fps goes below 10
1077 delta = 0.1;
1078 } else if (delta <= 0.0) { //unlikely but..
1079 delta = 0.001;
1080 }
1081 double todo = particles->frame_remainder + delta;
1082
1083 while (todo >= frame_time) {
1084 _particles_process(particles, frame_time);
1085 todo -= decr;
1086 }
1087
1088 particles->frame_remainder = todo;
1089
1090 } else {
1091 if (zero_time_scale) {
1092 _particles_process(particles, 0.0);
1093 } else {
1094 _particles_process(particles, RSG::rasterizer->get_frame_delta_time());
1095 }
1096 }
1097
1098 // Copy particles to instance buffer and pack Color/Custom.
1099 // We don't have camera information here, so don't copy here if we need camera information for view depth or align mode.
1100 if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
1101 _particles_update_instance_buffer(particles, Vector3(0.0, 0.0, 0.0), Vector3(0.0, 0.0, 0.0));
1102
1103 if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME && particles->sort_buffer_filled) {
1104 if (particles->mode == RS::ParticlesMode::PARTICLES_MODE_2D) {
1105 _particles_reverse_lifetime_sort<ParticleInstanceData2D>(particles);
1106 } else {
1107 _particles_reverse_lifetime_sort<ParticleInstanceData3D>(particles);
1108 }
1109 }
1110 }
1111
1112 SWAP(particles->front_instance_buffer, particles->back_instance_buffer);
1113
1114 // At the end of update, the back_buffer contains the most up-to-date-information to read from.
1115
1116 particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
1117 }
1118
1119 glDisable(GL_RASTERIZER_DISCARD);
1120}
1121
1122template <typename ParticleInstanceData>
1123void ParticlesStorage::_particles_reverse_lifetime_sort(Particles *particles) {
1124 glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);
1125
1126 ParticleInstanceData *particle_array;
1127 uint32_t buffer_size = particles->amount * sizeof(ParticleInstanceData);
1128#ifndef __EMSCRIPTEN__
1129 particle_array = static_cast<ParticleInstanceData *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, buffer_size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
1130
1131 ERR_FAIL_NULL(particle_array);
1132#else
1133 LocalVector<ParticleInstanceData> particle_vector;
1134 particle_vector.resize(particles->amount);
1135 particle_array = particle_vector.ptr();
1136 glGetBufferSubData(GL_ARRAY_BUFFER, 0, buffer_size, particle_array);
1137#endif
1138
1139 uint32_t lifetime_split = (MIN(int(particles->amount * particles->sort_buffer_phase), particles->amount - 1) + 1) % particles->amount;
1140 for (uint32_t i = 0; i < lifetime_split / 2; i++) {
1141 SWAP(particle_array[i], particle_array[lifetime_split - i - 1]);
1142 }
1143
1144 for (uint32_t i = 0; i < (particles->amount - lifetime_split) / 2; i++) {
1145 SWAP(particle_array[lifetime_split + i], particle_array[particles->amount - 1 - i]);
1146 }
1147
1148#ifndef __EMSCRIPTEN__
1149 glUnmapBuffer(GL_ARRAY_BUFFER);
1150#else
1151 glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_size, particle_vector.ptr());
1152#endif
1153 glBindBuffer(GL_ARRAY_BUFFER, 0);
1154}
1155
1156Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const {
1157 Particles *particles = particles_owner.get_or_null(p_particles);
1158 ERR_FAIL_NULL_V(particles, nullptr);
1159
1160 return &particles->dependency;
1161}
1162
1163bool ParticlesStorage::particles_is_inactive(RID p_particles) const {
1164 ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
1165 const Particles *particles = particles_owner.get_or_null(p_particles);
1166 ERR_FAIL_NULL_V(particles, false);
1167 return !particles->emitting && particles->inactive;
1168}
1169
1170/* PARTICLES COLLISION API */
1171
1172RID ParticlesStorage::particles_collision_allocate() {
1173 return particles_collision_owner.allocate_rid();
1174}
1175void ParticlesStorage::particles_collision_initialize(RID p_rid) {
1176 particles_collision_owner.initialize_rid(p_rid, ParticlesCollision());
1177}
1178
1179void ParticlesStorage::particles_collision_free(RID p_rid) {
1180 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_rid);
1181
1182 if (particles_collision->heightfield_texture != 0) {
1183 GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
1184 particles_collision->heightfield_texture = 0;
1185 glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
1186 particles_collision->heightfield_fb = 0;
1187 }
1188 particles_collision->dependency.deleted_notify(p_rid);
1189 particles_collision_owner.free(p_rid);
1190}
1191
1192GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
1193 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1194 ERR_FAIL_NULL_V(particles_collision, 0);
1195 ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, 0);
1196
1197 if (particles_collision->heightfield_texture == 0) {
1198 //create
1199 const int resolutions[RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX] = { 256, 512, 1024, 2048, 4096, 8192 };
1200 Size2i size;
1201 if (particles_collision->extents.x > particles_collision->extents.z) {
1202 size.x = resolutions[particles_collision->heightfield_resolution];
1203 size.y = int32_t(particles_collision->extents.z / particles_collision->extents.x * size.x);
1204 } else {
1205 size.y = resolutions[particles_collision->heightfield_resolution];
1206 size.x = int32_t(particles_collision->extents.x / particles_collision->extents.z * size.y);
1207 }
1208
1209 glGenTextures(1, &particles_collision->heightfield_texture);
1210 glActiveTexture(GL_TEXTURE0);
1211 glBindTexture(GL_TEXTURE_2D, particles_collision->heightfield_texture);
1212 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, size.x, size.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
1213
1214 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1215 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1216 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
1217 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
1218 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1219 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1220
1221 glGenFramebuffers(1, &particles_collision->heightfield_fb);
1222 glBindFramebuffer(GL_FRAMEBUFFER, particles_collision->heightfield_fb);
1223 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, particles_collision->heightfield_texture, 0);
1224#ifdef DEBUG_ENABLED
1225 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1226 if (status != GL_FRAMEBUFFER_COMPLETE) {
1227 WARN_PRINT("Could create heightmap texture status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
1228 }
1229#endif
1230 GLES3::Utilities::get_singleton()->texture_allocated_data(particles_collision->heightfield_texture, size.x * size.y * 4, "Particles collision heightfield texture");
1231
1232 particles_collision->heightfield_fb_size = size;
1233
1234 glBindTexture(GL_TEXTURE_2D, 0);
1235 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1236 }
1237
1238 return particles_collision->heightfield_fb;
1239}
1240
1241void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) {
1242 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1243 ERR_FAIL_NULL(particles_collision);
1244
1245 if (p_type == particles_collision->type) {
1246 return;
1247 }
1248
1249 if (particles_collision->heightfield_texture != 0) {
1250 GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
1251 particles_collision->heightfield_texture = 0;
1252 glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
1253 particles_collision->heightfield_fb = 0;
1254 }
1255
1256 particles_collision->type = p_type;
1257 particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
1258}
1259
1260void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) {
1261 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1262 ERR_FAIL_NULL(particles_collision);
1263 particles_collision->cull_mask = p_cull_mask;
1264}
1265
1266void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {
1267 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1268 ERR_FAIL_NULL(particles_collision);
1269
1270 particles_collision->radius = p_radius;
1271 particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
1272}
1273
1274void ParticlesStorage::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) {
1275 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1276 ERR_FAIL_NULL(particles_collision);
1277
1278 particles_collision->extents = p_extents;
1279 particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
1280}
1281
1282void ParticlesStorage::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) {
1283 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1284 ERR_FAIL_NULL(particles_collision);
1285
1286 particles_collision->attractor_strength = p_strength;
1287}
1288
1289void ParticlesStorage::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) {
1290 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1291 ERR_FAIL_NULL(particles_collision);
1292
1293 particles_collision->attractor_directionality = p_directionality;
1294}
1295
1296void ParticlesStorage::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) {
1297 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1298 ERR_FAIL_NULL(particles_collision);
1299
1300 particles_collision->attractor_attenuation = p_curve;
1301}
1302
1303void ParticlesStorage::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) {
1304 WARN_PRINT_ONCE_ED("The GL Compatibility rendering backend does not support SDF collisions in 3D particle shaders");
1305}
1306
1307void ParticlesStorage::particles_collision_height_field_update(RID p_particles_collision) {
1308 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1309 ERR_FAIL_NULL(particles_collision);
1310 particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
1311}
1312
1313void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
1314 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1315 ERR_FAIL_NULL(particles_collision);
1316 ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
1317
1318 if (particles_collision->heightfield_resolution == p_resolution) {
1319 return;
1320 }
1321
1322 particles_collision->heightfield_resolution = p_resolution;
1323
1324 if (particles_collision->heightfield_texture != 0) {
1325 GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);
1326 particles_collision->heightfield_texture = 0;
1327 glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
1328 particles_collision->heightfield_fb = 0;
1329 }
1330}
1331
1332AABB ParticlesStorage::particles_collision_get_aabb(RID p_particles_collision) const {
1333 ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1334 ERR_FAIL_NULL_V(particles_collision, AABB());
1335
1336 switch (particles_collision->type) {
1337 case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT:
1338 case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: {
1339 AABB aabb;
1340 aabb.position = -Vector3(1, 1, 1) * particles_collision->radius;
1341 aabb.size = Vector3(2, 2, 2) * particles_collision->radius;
1342 return aabb;
1343 }
1344 default: {
1345 AABB aabb;
1346 aabb.position = -particles_collision->extents;
1347 aabb.size = particles_collision->extents * 2;
1348 return aabb;
1349 }
1350 }
1351}
1352
1353Vector3 ParticlesStorage::particles_collision_get_extents(RID p_particles_collision) const {
1354 const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1355 ERR_FAIL_NULL_V(particles_collision, Vector3());
1356 return particles_collision->extents;
1357}
1358
1359bool ParticlesStorage::particles_collision_is_heightfield(RID p_particles_collision) const {
1360 const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
1361 ERR_FAIL_NULL_V(particles_collision, false);
1362 return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE;
1363}
1364
1365Dependency *ParticlesStorage::particles_collision_get_dependency(RID p_particles_collision) const {
1366 ParticlesCollision *pc = particles_collision_owner.get_or_null(p_particles_collision);
1367 ERR_FAIL_NULL_V(pc, nullptr);
1368
1369 return &pc->dependency;
1370}
1371
1372/* Particles collision instance */
1373
1374RID ParticlesStorage::particles_collision_instance_create(RID p_collision) {
1375 ParticlesCollisionInstance pci;
1376 pci.collision = p_collision;
1377 return particles_collision_instance_owner.make_rid(pci);
1378}
1379
1380void ParticlesStorage::particles_collision_instance_free(RID p_rid) {
1381 particles_collision_instance_owner.free(p_rid);
1382}
1383
1384void ParticlesStorage::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {
1385 ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
1386 ERR_FAIL_NULL(pci);
1387 pci->transform = p_transform;
1388}
1389
1390void ParticlesStorage::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) {
1391 ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
1392 ERR_FAIL_NULL(pci);
1393 pci->active = p_active;
1394}
1395
1396#endif // GLES3_ENABLED
1397