Path: blob/master/drivers/gles3/storage/particles_storage.cpp
10005 views
/**************************************************************************/1/* particles_storage.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#ifdef GLES3_ENABLED3132#include "particles_storage.h"3334#include "config.h"35#include "material_storage.h"36#include "mesh_storage.h"37#include "texture_storage.h"38#include "utilities.h"3940#include "servers/rendering/rendering_server_globals.h"4142using namespace GLES3;4344ParticlesStorage *ParticlesStorage::singleton = nullptr;4546ParticlesStorage *ParticlesStorage::get_singleton() {47return singleton;48}4950ParticlesStorage::ParticlesStorage() {51singleton = this;52GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();5354{55String global_defines;56global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now57material_storage->shaders.particles_process_shader.initialize(global_defines, 1);58}59{60// default material and shader for particles shader61particles_shader.default_shader = material_storage->shader_allocate();62material_storage->shader_initialize(particles_shader.default_shader);63material_storage->shader_set_code(particles_shader.default_shader, R"(64// Default particles shader.6566shader_type particles;6768void process() {69COLOR = vec4(1.0);70}71)");72particles_shader.default_material = material_storage->material_allocate();73material_storage->material_initialize(particles_shader.default_material);74material_storage->material_set_shader(particles_shader.default_material, particles_shader.default_shader);75}76{77particles_shader.copy_shader.initialize();78particles_shader.copy_shader_version = particles_shader.copy_shader.version_create();79}80}8182ParticlesStorage::~ParticlesStorage() {83singleton = nullptr;84GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();8586material_storage->material_free(particles_shader.default_material);87material_storage->shader_free(particles_shader.default_shader);88particles_shader.copy_shader.version_free(particles_shader.copy_shader_version);89}9091/* PARTICLES */9293RID ParticlesStorage::particles_allocate() {94return particles_owner.allocate_rid();95}9697void ParticlesStorage::particles_initialize(RID p_rid) {98particles_owner.initialize_rid(p_rid);99}100101void ParticlesStorage::particles_free(RID p_rid) {102Particles *particles = particles_owner.get_or_null(p_rid);103104particles->dependency.deleted_notify(p_rid);105particles->update_list.remove_from_list();106107_particles_free_data(particles);108particles_owner.free(p_rid);109}110111void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {112Particles *particles = particles_owner.get_or_null(p_particles);113ERR_FAIL_NULL(particles);114if (particles->mode == p_mode) {115return;116}117118_particles_free_data(particles);119120particles->mode = p_mode;121}122123void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) {124ERR_FAIL_COND_MSG(GLES3::Config::get_singleton()->disable_particles_workaround, "Due to driver bugs, GPUParticles are not supported on Adreno 3XX devices. Please use CPUParticles instead.");125126Particles *particles = particles_owner.get_or_null(p_particles);127ERR_FAIL_NULL(particles);128129particles->emitting = p_emitting;130}131132bool ParticlesStorage::particles_get_emitting(RID p_particles) {133if (GLES3::Config::get_singleton()->disable_particles_workaround) {134return false;135}136137Particles *particles = particles_owner.get_or_null(p_particles);138ERR_FAIL_NULL_V(particles, false);139140return particles->emitting;141}142143void ParticlesStorage::_particles_free_data(Particles *particles) {144particles->userdata_count = 0;145particles->instance_buffer_size_cache = 0;146particles->instance_buffer_stride_cache = 0;147particles->num_attrib_arrays_cache = 0;148particles->process_buffer_stride_cache = 0;149150if (particles->front_process_buffer != 0) {151glDeleteVertexArrays(1, &particles->front_vertex_array);152GLES3::Utilities::get_singleton()->buffer_free_data(particles->front_process_buffer);153GLES3::Utilities::get_singleton()->buffer_free_data(particles->front_instance_buffer);154particles->front_vertex_array = 0;155particles->front_process_buffer = 0;156particles->front_instance_buffer = 0;157158glDeleteVertexArrays(1, &particles->back_vertex_array);159GLES3::Utilities::get_singleton()->buffer_free_data(particles->back_process_buffer);160GLES3::Utilities::get_singleton()->buffer_free_data(particles->back_instance_buffer);161particles->back_vertex_array = 0;162particles->back_process_buffer = 0;163particles->back_instance_buffer = 0;164}165166if (particles->sort_buffer != 0) {167GLES3::Utilities::get_singleton()->buffer_free_data(particles->last_frame_buffer);168GLES3::Utilities::get_singleton()->buffer_free_data(particles->sort_buffer);169particles->last_frame_buffer = 0;170particles->sort_buffer = 0;171particles->sort_buffer_filled = false;172particles->last_frame_buffer_filled = false;173}174175if (particles->frame_params_ubo != 0) {176GLES3::Utilities::get_singleton()->buffer_free_data(particles->frame_params_ubo);177particles->frame_params_ubo = 0;178}179}180181void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {182Particles *particles = particles_owner.get_or_null(p_particles);183ERR_FAIL_NULL(particles);184185if (particles->amount == p_amount) {186return;187}188189_particles_free_data(particles);190191particles->amount = p_amount;192193particles->prev_ticks = 0;194particles->phase = 0;195particles->prev_phase = 0;196particles->clear = true;197198particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);199}200201void ParticlesStorage::particles_set_amount_ratio(RID p_particles, float p_amount_ratio) {202Particles *particles = particles_owner.get_or_null(p_particles);203ERR_FAIL_NULL(particles);204205particles->amount_ratio = p_amount_ratio;206}207208void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {209Particles *particles = particles_owner.get_or_null(p_particles);210ERR_FAIL_NULL(particles);211particles->lifetime = p_lifetime;212}213214void ParticlesStorage::particles_set_one_shot(RID p_particles, bool p_one_shot) {215Particles *particles = particles_owner.get_or_null(p_particles);216ERR_FAIL_NULL(particles);217particles->one_shot = p_one_shot;218}219220void ParticlesStorage::particles_set_pre_process_time(RID p_particles, double p_time) {221Particles *particles = particles_owner.get_or_null(p_particles);222ERR_FAIL_NULL(particles);223particles->pre_process_time = p_time;224}225226void ParticlesStorage::particles_request_process_time(RID p_particles, real_t p_request_process_time) {227Particles *particles = particles_owner.get_or_null(p_particles);228ERR_FAIL_NULL(particles);229particles->request_process_time = p_request_process_time;230}231232void ParticlesStorage::particles_set_seed(RID p_particles, uint32_t p_seed) {233Particles *particles = particles_owner.get_or_null(p_particles);234ERR_FAIL_NULL(particles);235particles->random_seed = p_seed;236}237238void ParticlesStorage::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) {239Particles *particles = particles_owner.get_or_null(p_particles);240ERR_FAIL_NULL(particles);241particles->explosiveness = p_ratio;242}243void ParticlesStorage::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) {244Particles *particles = particles_owner.get_or_null(p_particles);245ERR_FAIL_NULL(particles);246particles->randomness = p_ratio;247}248249void ParticlesStorage::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {250Particles *particles = particles_owner.get_or_null(p_particles);251ERR_FAIL_NULL(particles);252particles->custom_aabb = p_aabb;253particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);254}255256void ParticlesStorage::particles_set_speed_scale(RID p_particles, double p_scale) {257Particles *particles = particles_owner.get_or_null(p_particles);258ERR_FAIL_NULL(particles);259260particles->speed_scale = p_scale;261}262void ParticlesStorage::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {263Particles *particles = particles_owner.get_or_null(p_particles);264ERR_FAIL_NULL(particles);265266particles->use_local_coords = p_enable;267particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);268}269270void ParticlesStorage::particles_set_fixed_fps(RID p_particles, int p_fps) {271Particles *particles = particles_owner.get_or_null(p_particles);272ERR_FAIL_NULL(particles);273274particles->fixed_fps = p_fps;275276_particles_free_data(particles);277278particles->prev_ticks = 0;279particles->phase = 0;280particles->prev_phase = 0;281particles->clear = true;282283particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);284}285286void ParticlesStorage::particles_set_interpolate(RID p_particles, bool p_enable) {287Particles *particles = particles_owner.get_or_null(p_particles);288ERR_FAIL_NULL(particles);289290particles->interpolate = p_enable;291}292293void ParticlesStorage::particles_set_fractional_delta(RID p_particles, bool p_enable) {294Particles *particles = particles_owner.get_or_null(p_particles);295ERR_FAIL_NULL(particles);296297particles->fractional_delta = p_enable;298}299300void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, double p_length) {301if (p_enable) {302WARN_PRINT_ONCE_ED("The Compatibility renderer does not support particle trails.");303}304}305306void ParticlesStorage::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {307if (p_bind_poses.size() != 0) {308WARN_PRINT_ONCE_ED("The Compatibility renderer does not support particle trails.");309}310}311312void ParticlesStorage::particles_set_collision_base_size(RID p_particles, real_t p_size) {313Particles *particles = particles_owner.get_or_null(p_particles);314ERR_FAIL_NULL(particles);315316particles->collision_base_size = p_size;317}318319void ParticlesStorage::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {320Particles *particles = particles_owner.get_or_null(p_particles);321ERR_FAIL_NULL(particles);322323particles->transform_align = p_transform_align;324}325326void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) {327Particles *particles = particles_owner.get_or_null(p_particles);328ERR_FAIL_NULL(particles);329330particles->process_material = p_material;331particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES); //the instance buffer may have changed332}333334RID ParticlesStorage::particles_get_process_material(RID p_particles) const {335Particles *particles = particles_owner.get_or_null(p_particles);336ERR_FAIL_NULL_V(particles, RID());337338return particles->process_material;339}340341void ParticlesStorage::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {342Particles *particles = particles_owner.get_or_null(p_particles);343ERR_FAIL_NULL(particles);344345particles->draw_order = p_order;346}347348void ParticlesStorage::particles_set_draw_passes(RID p_particles, int p_passes) {349Particles *particles = particles_owner.get_or_null(p_particles);350ERR_FAIL_NULL(particles);351352particles->draw_passes.resize(p_passes);353}354355void ParticlesStorage::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {356Particles *particles = particles_owner.get_or_null(p_particles);357ERR_FAIL_NULL(particles);358ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());359particles->draw_passes.write[p_pass] = p_mesh;360particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);361}362363void ParticlesStorage::particles_restart(RID p_particles) {364Particles *particles = particles_owner.get_or_null(p_particles);365ERR_FAIL_NULL(particles);366367particles->restart_request = true;368}369370void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {371if (p_subemitter_particles.is_valid()) {372WARN_PRINT_ONCE_ED("The Compatibility renderer does not support particle sub-emitters.");373}374}375376void 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) {377WARN_PRINT_ONCE_ED("The Compatibility renderer does not support manually emitting particles.");378}379380void ParticlesStorage::particles_request_process(RID p_particles) {381Particles *particles = particles_owner.get_or_null(p_particles);382ERR_FAIL_NULL(particles);383384if (!particles->dirty) {385particles->dirty = true;386387if (!particles->update_list.in_list()) {388particle_update_list.add(&particles->update_list);389}390}391}392393AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) {394const Particles *particles = particles_owner.get_or_null(p_particles);395ERR_FAIL_NULL_V(particles, AABB());396397int total_amount = particles->amount;398399// If available, read from the sort buffer which should be 2 frames out of date.400// This will help alleviate GPU stalls.401GLuint read_buffer = particles->sort_buffer_filled ? particles->sort_buffer : particles->back_instance_buffer;402403Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, read_buffer, total_amount * sizeof(ParticleInstanceData3D));404ERR_FAIL_COND_V(buffer.size() != (int)(total_amount * sizeof(ParticleInstanceData3D)), AABB());405406Transform3D inv = particles->emission_transform.affine_inverse();407408AABB aabb;409if (buffer.size()) {410bool first = true;411412const uint8_t *data_ptr = (const uint8_t *)buffer.ptr();413uint32_t particle_data_size = sizeof(ParticleInstanceData3D);414415for (int i = 0; i < total_amount; i++) {416const ParticleInstanceData3D &particle_data = *(const ParticleInstanceData3D *)&data_ptr[particle_data_size * i];417// If scale is 0.0, we assume the particle is inactive.418if (particle_data.xform[0] > 0.0) {419Vector3 pos = Vector3(particle_data.xform[3], particle_data.xform[7], particle_data.xform[11]);420if (!particles->use_local_coords) {421pos = inv.xform(pos);422}423if (first) {424aabb.position = pos;425first = false;426} else {427aabb.expand_to(pos);428}429}430}431}432433float longest_axis_size = 0;434for (int i = 0; i < particles->draw_passes.size(); i++) {435if (particles->draw_passes[i].is_valid()) {436AABB maabb = MeshStorage::get_singleton()->mesh_get_aabb(particles->draw_passes[i], RID());437longest_axis_size = MAX(maabb.get_longest_axis_size(), longest_axis_size);438}439}440441aabb.grow_by(longest_axis_size);442443return aabb;444}445446AABB ParticlesStorage::particles_get_aabb(RID p_particles) const {447const Particles *particles = particles_owner.get_or_null(p_particles);448ERR_FAIL_NULL_V(particles, AABB());449450return particles->custom_aabb;451}452453void ParticlesStorage::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {454Particles *particles = particles_owner.get_or_null(p_particles);455ERR_FAIL_NULL(particles);456457particles->emission_transform = p_transform;458}459460void ParticlesStorage::particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) {461Particles *particles = particles_owner.get_or_null(p_particles);462ERR_FAIL_NULL(particles);463464particles->emitter_velocity = p_velocity;465}466467void ParticlesStorage::particles_set_interp_to_end(RID p_particles, float p_interp) {468Particles *particles = particles_owner.get_or_null(p_particles);469ERR_FAIL_NULL(particles);470471particles->interp_to_end = p_interp;472}473474int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {475const Particles *particles = particles_owner.get_or_null(p_particles);476ERR_FAIL_NULL_V(particles, 0);477478return particles->draw_passes.size();479}480481RID ParticlesStorage::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {482const Particles *particles = particles_owner.get_or_null(p_particles);483ERR_FAIL_NULL_V(particles, RID());484ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID());485486return particles->draw_passes[p_pass];487}488489void ParticlesStorage::particles_add_collision(RID p_particles, RID p_particles_collision_instance) {490Particles *particles = particles_owner.get_or_null(p_particles);491ERR_FAIL_NULL(particles);492particles->collisions.insert(p_particles_collision_instance);493}494495void ParticlesStorage::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) {496Particles *particles = particles_owner.get_or_null(p_particles);497ERR_FAIL_NULL(particles);498particles->collisions.erase(p_particles_collision_instance);499}500501void ParticlesStorage::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, GLuint p_texture) {502Particles *particles = particles_owner.get_or_null(p_particles);503ERR_FAIL_NULL(particles);504particles->has_sdf_collision = p_enable;505particles->sdf_collision_transform = p_xform;506particles->sdf_collision_to_screen = p_to_screen;507particles->sdf_collision_texture = p_texture;508}509510// Does one step of processing particles by reading from back_process_buffer and writing to front_process_buffer.511void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta) {512GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();513GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();514515double new_phase = Math::fmod(p_particles->phase + (p_delta / p_particles->lifetime), 1.0);516517//update current frame518ParticlesFrameParams frame_params;519520if (p_particles->clear) {521p_particles->cycle_number = 0;522} else if (new_phase < p_particles->phase) {523if (p_particles->one_shot) {524p_particles->emitting = false;525}526p_particles->cycle_number++;527}528529frame_params.emitting = p_particles->emitting;530frame_params.system_phase = new_phase;531frame_params.prev_system_phase = p_particles->phase;532533p_particles->phase = new_phase;534535frame_params.time = RSG::rasterizer->get_total_time();536frame_params.delta = p_delta;537frame_params.random_seed = p_particles->random_seed;538frame_params.explosiveness = p_particles->explosiveness;539frame_params.randomness = p_particles->randomness;540541if (p_particles->use_local_coords) {542GLES3::MaterialStorage::store_transform(Transform3D(), frame_params.emission_transform);543} else {544GLES3::MaterialStorage::store_transform(p_particles->emission_transform, frame_params.emission_transform);545}546547frame_params.cycle = p_particles->cycle_number;548frame_params.frame = p_particles->frame_counter++;549frame_params.amount_ratio = p_particles->amount_ratio;550frame_params.pad1 = 0;551frame_params.pad2 = 0;552frame_params.interp_to_end = p_particles->interp_to_end;553frame_params.emitter_velocity[0] = p_particles->emitter_velocity.x;554frame_params.emitter_velocity[1] = p_particles->emitter_velocity.y;555frame_params.emitter_velocity[2] = p_particles->emitter_velocity.z;556557{ //collision and attractors558559frame_params.collider_count = 0;560frame_params.attractor_count = 0;561frame_params.particle_size = p_particles->collision_base_size;562563GLuint collision_heightmap_texture = 0;564565Transform3D to_particles;566if (p_particles->use_local_coords) {567to_particles = p_particles->emission_transform.affine_inverse();568}569570if (p_particles->has_sdf_collision && p_particles->sdf_collision_texture != 0) {571//2D collision572573Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand574575if (!p_particles->use_local_coords) {576Transform2D emission;577emission.columns[0] = Vector2(p_particles->emission_transform.basis.get_column(0).x, p_particles->emission_transform.basis.get_column(0).y);578emission.columns[1] = Vector2(p_particles->emission_transform.basis.get_column(1).x, p_particles->emission_transform.basis.get_column(1).y);579emission.set_origin(Vector2(p_particles->emission_transform.origin.x, p_particles->emission_transform.origin.y));580xform = xform * emission.affine_inverse();581}582583Transform2D revert = xform.affine_inverse();584frame_params.collider_count = 1;585frame_params.colliders[0].transform[0] = xform.columns[0][0];586frame_params.colliders[0].transform[1] = xform.columns[0][1];587frame_params.colliders[0].transform[2] = 0;588frame_params.colliders[0].transform[3] = xform.columns[2][0];589590frame_params.colliders[0].transform[4] = xform.columns[1][0];591frame_params.colliders[0].transform[5] = xform.columns[1][1];592frame_params.colliders[0].transform[6] = 0;593frame_params.colliders[0].transform[7] = xform.columns[2][1];594595frame_params.colliders[0].transform[8] = revert.columns[0][0];596frame_params.colliders[0].transform[9] = revert.columns[0][1];597frame_params.colliders[0].transform[10] = 0;598frame_params.colliders[0].transform[11] = revert.columns[2][0];599600frame_params.colliders[0].transform[12] = revert.columns[1][0];601frame_params.colliders[0].transform[13] = revert.columns[1][1];602frame_params.colliders[0].transform[14] = 0;603frame_params.colliders[0].transform[15] = revert.columns[2][1];604605frame_params.colliders[0].extents[0] = p_particles->sdf_collision_to_screen.size.x;606frame_params.colliders[0].extents[1] = p_particles->sdf_collision_to_screen.size.y;607frame_params.colliders[0].extents[2] = p_particles->sdf_collision_to_screen.position.x;608frame_params.colliders[0].scale = p_particles->sdf_collision_to_screen.position.y;609frame_params.colliders[0].type = ParticlesFrameParams::COLLISION_TYPE_2D_SDF;610611collision_heightmap_texture = p_particles->sdf_collision_texture;612}613614for (const RID &E : p_particles->collisions) {615ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(E);616if (!pci || !pci->active) {617continue;618}619ParticlesCollision *pc = particles_collision_owner.get_or_null(pci->collision);620ERR_CONTINUE(!pc);621622Transform3D to_collider = pci->transform;623if (p_particles->use_local_coords) {624to_collider = to_particles * to_collider;625}626Vector3 scale = to_collider.basis.get_scale();627to_collider.basis.orthonormalize();628629if (pc->type <= RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT) {630//attractor631if (frame_params.attractor_count >= ParticlesFrameParams::MAX_ATTRACTORS) {632continue;633}634635ParticlesFrameParams::Attractor &attr = frame_params.attractors[frame_params.attractor_count];636637GLES3::MaterialStorage::store_transform(to_collider, attr.transform);638attr.strength = pc->attractor_strength;639attr.attenuation = pc->attractor_attenuation;640attr.directionality = pc->attractor_directionality;641642switch (pc->type) {643case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT: {644attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_SPHERE;645float radius = pc->radius;646radius *= (scale.x + scale.y + scale.z) / 3.0;647attr.extents[0] = radius;648attr.extents[1] = radius;649attr.extents[2] = radius;650} break;651case RS::PARTICLES_COLLISION_TYPE_BOX_ATTRACT: {652attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_BOX;653Vector3 extents = pc->extents * scale;654attr.extents[0] = extents.x;655attr.extents[1] = extents.y;656attr.extents[2] = extents.z;657} break;658case RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT: {659WARN_PRINT_ONCE_ED("Vector field particle attractors are not available in the Compatibility renderer.");660} break;661default: {662}663}664665frame_params.attractor_count++;666} else {667//collider668if (frame_params.collider_count >= ParticlesFrameParams::MAX_COLLIDERS) {669continue;670}671672ParticlesFrameParams::Collider &col = frame_params.colliders[frame_params.collider_count];673674GLES3::MaterialStorage::store_transform(to_collider, col.transform);675switch (pc->type) {676case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: {677col.type = ParticlesFrameParams::COLLISION_TYPE_SPHERE;678float radius = pc->radius;679radius *= (scale.x + scale.y + scale.z) / 3.0;680col.extents[0] = radius;681col.extents[1] = radius;682col.extents[2] = radius;683} break;684case RS::PARTICLES_COLLISION_TYPE_BOX_COLLIDE: {685col.type = ParticlesFrameParams::COLLISION_TYPE_BOX;686Vector3 extents = pc->extents * scale;687col.extents[0] = extents.x;688col.extents[1] = extents.y;689col.extents[2] = extents.z;690} break;691case RS::PARTICLES_COLLISION_TYPE_SDF_COLLIDE: {692WARN_PRINT_ONCE_ED("SDF Particle Colliders are not available in the Compatibility renderer.");693} break;694case RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE: {695if (collision_heightmap_texture != 0) { //already taken696continue;697}698699col.type = ParticlesFrameParams::COLLISION_TYPE_HEIGHT_FIELD;700Vector3 extents = pc->extents * scale;701col.extents[0] = extents.x;702col.extents[1] = extents.y;703col.extents[2] = extents.z;704collision_heightmap_texture = pc->heightfield_texture;705} break;706default: {707}708}709710frame_params.collider_count++;711}712}713714// Bind heightmap or SDF texture.715GLuint heightmap = collision_heightmap_texture;716if (heightmap == 0) {717GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_BLACK));718heightmap = tex->tex_id;719}720glActiveTexture(GL_TEXTURE0);721glBindTexture(GL_TEXTURE_2D, heightmap);722}723724if (p_particles->frame_params_ubo == 0) {725glGenBuffers(1, &p_particles->frame_params_ubo);726glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);727GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, p_particles->frame_params_ubo, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW, "Particle Frame UBO");728} else {729// Update per-frame UBO.730glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);731glBufferData(GL_UNIFORM_BUFFER, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW);732}733734// Get shader and set shader uniforms;735ParticleProcessMaterialData *m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(p_particles->process_material, RS::SHADER_PARTICLES));736if (!m) {737m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, RS::SHADER_PARTICLES));738}739740ERR_FAIL_NULL(m);741742ParticlesShaderGLES3::ShaderVariant variant = ParticlesShaderGLES3::MODE_DEFAULT;743744uint32_t specialization = 0;745for (uint32_t i = 0; i < PARTICLES_MAX_USERDATAS; i++) {746if (m->shader_data->userdatas_used[i]) {747specialization |= ParticlesShaderGLES3::USERDATA1_USED << i;748}749}750751if (p_particles->mode == RS::ParticlesMode::PARTICLES_MODE_3D) {752specialization |= ParticlesShaderGLES3::MODE_3D;753}754755RID version = particles_shader.default_shader_version;756if (m->shader_data->version.is_valid() && m->shader_data->valid) {757// Bind material uniform buffer and textures.758m->bind_uniforms();759version = m->shader_data->version;760}761762bool success = material_storage->shaders.particles_process_shader.version_bind_shader(version, variant, specialization);763if (!success) {764return;765}766767material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::LIFETIME, p_particles->lifetime, version, variant, specialization);768material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::CLEAR, p_particles->clear, version, variant, specialization);769material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::TOTAL_PARTICLES, uint32_t(p_particles->amount), version, variant, specialization);770material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::USE_FRACTIONAL_DELTA, p_particles->fractional_delta, version, variant, specialization);771772p_particles->clear = false;773774p_particles->has_collision_cache = m->shader_data->uses_collision;775776glBindVertexArray(p_particles->back_vertex_array);777778glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, p_particles->front_process_buffer);779780glBeginTransformFeedback(GL_POINTS);781glDrawArrays(GL_POINTS, 0, p_particles->amount);782glEndTransformFeedback();783784glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);785glBindVertexArray(0);786787SWAP(p_particles->front_process_buffer, p_particles->back_process_buffer);788SWAP(p_particles->front_vertex_array, p_particles->back_vertex_array);789}790791void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {792Particles *particles = particles_owner.get_or_null(p_particles);793ERR_FAIL_NULL(particles);794795if (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) {796return;797}798799if (particles->front_process_buffer == 0) {800return; //particles have not processed yet801}802803Vector3 axis = -p_axis; // cameras look to z negative804805if (particles->use_local_coords) {806axis = particles->emission_transform.basis.xform_inv(axis).normalized();807}808809// Sort will be done on CPU since we don't have compute shaders.810// If the sort_buffer has valid data811// Use a buffer that is 2 frames out of date to avoid stalls.812if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->sort_buffer_filled) {813glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);814815ParticleInstanceData3D *particle_array;816#ifndef __EMSCRIPTEN__817particle_array = static_cast<ParticleInstanceData3D *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));818ERR_FAIL_NULL(particle_array);819#else820LocalVector<ParticleInstanceData3D> particle_vector;821particle_vector.resize(particles->amount);822particle_array = particle_vector.ptr();823godot_webgl2_glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), particle_array);824#endif825SortArray<ParticleInstanceData3D, ParticlesViewSort> sorter;826sorter.compare.z_dir = axis;827sorter.sort(particle_array, particles->amount);828829#ifndef __EMSCRIPTEN__830glUnmapBuffer(GL_ARRAY_BUFFER);831#else832glBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), particle_vector.ptr());833#endif834}835836glEnable(GL_RASTERIZER_DISCARD);837glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);838_particles_update_instance_buffer(particles, axis, p_up_axis);839glDisable(GL_RASTERIZER_DISCARD);840}841842void ParticlesStorage::_particles_update_buffers(Particles *particles) {843GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();844uint32_t userdata_count = 0;845846if (particles->process_material.is_valid()) {847GLES3::ParticleProcessMaterialData *material_data = static_cast<GLES3::ParticleProcessMaterialData *>(material_storage->material_get_data(particles->process_material, RS::SHADER_PARTICLES));848if (material_data && material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {849userdata_count = material_data->shader_data->userdata_count;850}851}852853if (userdata_count != particles->userdata_count) {854// Mismatch userdata, re-create buffers.855_particles_free_data(particles);856}857858if (particles->amount > 0 && particles->front_process_buffer == 0) {859int total_amount = particles->amount;860861particles->userdata_count = userdata_count;862863uint32_t xform_size = particles->mode == RS::PARTICLES_MODE_2D ? 2 : 3;864particles->instance_buffer_stride_cache = sizeof(float) * 4 * (xform_size + 1);865particles->instance_buffer_size_cache = particles->instance_buffer_stride_cache * total_amount;866particles->num_attrib_arrays_cache = 5 + userdata_count + (xform_size - 2);867particles->process_buffer_stride_cache = sizeof(float) * 4 * particles->num_attrib_arrays_cache;868869PackedByteArray data;870data.resize_initialized(particles->process_buffer_stride_cache * total_amount);871872PackedByteArray instance_data;873instance_data.resize_initialized(particles->instance_buffer_size_cache);874875{876glGenVertexArrays(1, &particles->front_vertex_array);877glBindVertexArray(particles->front_vertex_array);878glGenBuffers(1, &particles->front_process_buffer);879glGenBuffers(1, &particles->front_instance_buffer);880881glBindBuffer(GL_ARRAY_BUFFER, particles->front_process_buffer);882GLES3::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");883884for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {885glEnableVertexAttribArray(j);886glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, particles->process_buffer_stride_cache, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));887}888glBindVertexArray(0);889890glBindBuffer(GL_ARRAY_BUFFER, particles->front_instance_buffer);891GLES3::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");892}893894{895glGenVertexArrays(1, &particles->back_vertex_array);896glBindVertexArray(particles->back_vertex_array);897glGenBuffers(1, &particles->back_process_buffer);898glGenBuffers(1, &particles->back_instance_buffer);899900glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);901GLES3::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");902903for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {904glEnableVertexAttribArray(j);905glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, particles->process_buffer_stride_cache, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));906}907glBindVertexArray(0);908909glBindBuffer(GL_ARRAY_BUFFER, particles->back_instance_buffer);910GLES3::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");911}912glBindBuffer(GL_ARRAY_BUFFER, 0);913}914}915916void ParticlesStorage::_particles_allocate_history_buffers(Particles *particles) {917if (particles->sort_buffer == 0) {918glGenBuffers(1, &particles->last_frame_buffer);919glBindBuffer(GL_ARRAY_BUFFER, particles->last_frame_buffer);920GLES3::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");921922glGenBuffers(1, &particles->sort_buffer);923glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);924GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, particles->sort_buffer, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ, "Particles sort buffer");925926particles->sort_buffer_filled = false;927particles->last_frame_buffer_filled = false;928glBindBuffer(GL_ARRAY_BUFFER, 0);929}930}931void ParticlesStorage::_particles_update_instance_buffer(Particles *particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {932ParticlesCopyShaderGLES3::ShaderVariant variant = ParticlesCopyShaderGLES3::MODE_DEFAULT;933934uint64_t specialization = 0;935if (particles->mode == RS::ParticlesMode::PARTICLES_MODE_3D) {936specialization |= ParticlesCopyShaderGLES3::MODE_3D;937}938939bool success = particles_shader.copy_shader.version_bind_shader(particles_shader.copy_shader_version, variant, specialization);940if (!success) {941return;942}943944// Affect 2D only.945if (particles->use_local_coords) {946// In local mode, particle positions are calculated locally (relative to the node position)947// and they're also drawn locally.948// It works as expected, so we just pass an identity transform.949particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::INV_EMISSION_TRANSFORM, Transform3D(), particles_shader.copy_shader_version, variant, specialization);950} else {951// In global mode, particle positions are calculated globally (relative to the canvas origin)952// but they're drawn locally.953// So, we need to pass the inverse of the emission transform to bring the954// particles to local coordinates before drawing.955Transform3D inv = particles->emission_transform.affine_inverse();956particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::INV_EMISSION_TRANSFORM, inv, particles_shader.copy_shader_version, variant, specialization);957}958959particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::FRAME_REMAINDER, particles->interpolate ? particles->frame_remainder : 0.0, particles_shader.copy_shader_version, variant, specialization);960particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::ALIGN_MODE, uint32_t(particles->transform_align), particles_shader.copy_shader_version, variant, specialization);961particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::ALIGN_UP, p_up_axis, particles_shader.copy_shader_version, variant, specialization);962particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::SORT_DIRECTION, p_axis, particles_shader.copy_shader_version, variant, specialization);963964glBindVertexArray(particles->back_vertex_array);965glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->front_instance_buffer, 0, particles->instance_buffer_size_cache);966glBeginTransformFeedback(GL_POINTS);967968if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME) {969uint32_t lifetime_split = (MIN(int(particles->amount * particles->phase), particles->amount - 1) + 1) % particles->amount;970uint32_t stride = particles->process_buffer_stride_cache;971972glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);973974// Offset VBO so you render starting at the newest particle.975if (particles->amount - lifetime_split > 0) {976glEnableVertexAttribArray(0); // Color.977glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 0));978glEnableVertexAttribArray(1); // .xyz: velocity. .z: flags.979glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 1));980glEnableVertexAttribArray(2); // Custom.981glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 2));982glEnableVertexAttribArray(3); // Xform1.983glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 3));984glEnableVertexAttribArray(4); // Xform2.985glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 4));986if (particles->mode == RS::PARTICLES_MODE_3D) {987glEnableVertexAttribArray(5); // Xform3.988glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 5));989}990991uint32_t to_draw = particles->amount - lifetime_split;992glDrawArrays(GL_POINTS, 0, to_draw);993}994995// Then render from index 0 up intil the newest particle.996if (lifetime_split > 0) {997glEndTransformFeedback();998// Now output to the second portion of the instance buffer.999glBindBufferRange(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));1000glBeginTransformFeedback(GL_POINTS);1001// Reset back to normal.1002for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {1003glEnableVertexAttribArray(j);1004glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));1005}10061007glDrawArrays(GL_POINTS, 0, lifetime_split);1008}1009} else {1010glDrawArrays(GL_POINTS, 0, particles->amount);1011}10121013glEndTransformFeedback();1014glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, 0, 0);1015glBindVertexArray(0);1016glBindBuffer(GL_ARRAY_BUFFER, 0);1017}10181019void ParticlesStorage::update_particles() {1020if (!particle_update_list.first()) {1021// Return early to avoid unnecessary state changes.1022return;1023}10241025RENDER_TIMESTAMP("Update GPUParticles");1026glEnable(GL_RASTERIZER_DISCARD);1027glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);10281029GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer();10301031glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_GLOBALS_UNIFORM_LOCATION, global_buffer);1032glBindBuffer(GL_UNIFORM_BUFFER, 0);10331034while (particle_update_list.first()) {1035// Use transform feedback to process particles.10361037Particles *particles = particle_update_list.first()->self();10381039particles->update_list.remove_from_list();1040particles->dirty = false;10411042_particles_update_buffers(particles);10431044if (particles->restart_request) {1045particles->prev_ticks = 0;1046particles->phase = 0;1047particles->prev_phase = 0;1048particles->clear = true;1049particles->restart_request = false;1050}10511052if (particles->inactive && !particles->emitting) {1053//go next1054continue;1055}10561057if (particles->emitting) {1058if (particles->inactive) {1059//restart system from scratch1060particles->prev_ticks = 0;1061particles->phase = 0;1062particles->prev_phase = 0;1063particles->clear = true;1064}1065particles->inactive = false;1066particles->inactive_time = 0;1067} else {1068particles->inactive_time += particles->speed_scale * RSG::rasterizer->get_frame_delta_time();1069if (particles->inactive_time > particles->lifetime * 1.2) {1070particles->inactive = true;1071continue;1072}1073}10741075// Copy the instance buffer that was last used into the last_frame buffer.1076// sort_buffer should now be 2 frames out of date.1077if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME) {1078_particles_allocate_history_buffers(particles);1079SWAP(particles->last_frame_buffer, particles->sort_buffer);10801081glBindBuffer(GL_COPY_READ_BUFFER, particles->back_instance_buffer);1082glBindBuffer(GL_COPY_WRITE_BUFFER, particles->last_frame_buffer);1083glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, particles->instance_buffer_size_cache);10841085// Last frame's last_frame turned into this frame's sort buffer.1086particles->sort_buffer_filled = particles->last_frame_buffer_filled;1087particles->sort_buffer_phase = particles->last_frame_phase;1088particles->last_frame_buffer_filled = true;1089particles->last_frame_phase = particles->phase;1090glBindBuffer(GL_COPY_READ_BUFFER, 0);1091glBindBuffer(GL_COPY_WRITE_BUFFER, 0);1092}10931094int fixed_fps = 0;1095if (particles->fixed_fps > 0) {1096fixed_fps = particles->fixed_fps;1097}10981099if (particles->clear && particles->pre_process_time > 0.0) {1100double frame_time;1101if (fixed_fps > 0) {1102frame_time = 1.0 / fixed_fps;1103} else {1104frame_time = 1.0 / 30.0;1105}11061107double todo = particles->pre_process_time;11081109while (todo >= 0) {1110_particles_process(particles, frame_time);1111todo -= frame_time;1112}1113}11141115double time_scale = MAX(particles->speed_scale, 0.0);11161117if (fixed_fps > 0) {1118double frame_time = 1.0 / fixed_fps;1119double delta = RSG::rasterizer->get_frame_delta_time();1120if (delta > 0.1) { //avoid recursive stalls if fps goes below 101121delta = 0.1;1122} else if (delta <= 0.0) { //unlikely but..1123delta = 0.001;1124}1125double todo = particles->frame_remainder + delta * time_scale;11261127while (todo >= frame_time) {1128_particles_process(particles, frame_time);1129todo -= frame_time;1130}11311132particles->frame_remainder = todo;11331134} else {1135_particles_process(particles, RSG::rasterizer->get_frame_delta_time() * time_scale);1136}11371138if (particles->request_process_time > 0.0) {1139double frame_time;1140if (fixed_fps > 0) {1141frame_time = 1.0 / fixed_fps;1142} else {1143frame_time = 1.0 / 30.0;1144}1145float tmp_scale = particles->speed_scale;1146particles->speed_scale = 1.0;1147double todo = particles->request_process_time;1148while (todo >= 0) {1149_particles_process(particles, frame_time);1150todo -= frame_time;1151}1152particles->speed_scale = tmp_scale;1153particles->request_process_time = 0.0;1154}11551156// Copy particles to instance buffer and pack Color/Custom.1157// We don't have camera information here, so don't copy here if we need camera information for view depth or align mode.1158if (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) {1159_particles_update_instance_buffer(particles, Vector3(0.0, 0.0, 0.0), Vector3(0.0, 0.0, 0.0));11601161if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME && particles->sort_buffer_filled) {1162if (particles->mode == RS::ParticlesMode::PARTICLES_MODE_2D) {1163_particles_reverse_lifetime_sort<ParticleInstanceData2D>(particles);1164} else {1165_particles_reverse_lifetime_sort<ParticleInstanceData3D>(particles);1166}1167}1168}11691170SWAP(particles->front_instance_buffer, particles->back_instance_buffer);11711172// At the end of update, the back_buffer contains the most up-to-date-information to read from.11731174particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);1175}11761177glDisable(GL_RASTERIZER_DISCARD);1178}11791180template <typename ParticleInstanceData>1181void ParticlesStorage::_particles_reverse_lifetime_sort(Particles *particles) {1182glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);11831184ParticleInstanceData *particle_array;1185uint32_t buffer_size = particles->amount * sizeof(ParticleInstanceData);1186#ifndef __EMSCRIPTEN__1187particle_array = static_cast<ParticleInstanceData *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, buffer_size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));11881189ERR_FAIL_NULL(particle_array);1190#else1191LocalVector<ParticleInstanceData> particle_vector;1192particle_vector.resize(particles->amount);1193particle_array = particle_vector.ptr();1194godot_webgl2_glGetBufferSubData(GL_ARRAY_BUFFER, 0, buffer_size, particle_array);1195#endif11961197uint32_t lifetime_split = (MIN(int(particles->amount * particles->sort_buffer_phase), particles->amount - 1) + 1) % particles->amount;1198for (uint32_t i = 0; i < lifetime_split / 2; i++) {1199SWAP(particle_array[i], particle_array[lifetime_split - i - 1]);1200}12011202for (uint32_t i = 0; i < (particles->amount - lifetime_split) / 2; i++) {1203SWAP(particle_array[lifetime_split + i], particle_array[particles->amount - 1 - i]);1204}12051206#ifndef __EMSCRIPTEN__1207glUnmapBuffer(GL_ARRAY_BUFFER);1208#else1209glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_size, particle_vector.ptr());1210#endif1211glBindBuffer(GL_ARRAY_BUFFER, 0);1212}12131214Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const {1215Particles *particles = particles_owner.get_or_null(p_particles);1216ERR_FAIL_NULL_V(particles, nullptr);12171218return &particles->dependency;1219}12201221bool ParticlesStorage::particles_is_inactive(RID p_particles) const {1222const Particles *particles = particles_owner.get_or_null(p_particles);1223ERR_FAIL_NULL_V(particles, false);1224return !particles->emitting && particles->inactive;1225}12261227/* PARTICLES COLLISION API */12281229RID ParticlesStorage::particles_collision_allocate() {1230return particles_collision_owner.allocate_rid();1231}1232void ParticlesStorage::particles_collision_initialize(RID p_rid) {1233particles_collision_owner.initialize_rid(p_rid, ParticlesCollision());1234}12351236void ParticlesStorage::particles_collision_free(RID p_rid) {1237ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_rid);12381239if (particles_collision->heightfield_texture != 0) {1240GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);1241particles_collision->heightfield_texture = 0;1242glDeleteFramebuffers(1, &particles_collision->heightfield_fb);1243particles_collision->heightfield_fb = 0;1244}1245particles_collision->dependency.deleted_notify(p_rid);1246particles_collision_owner.free(p_rid);1247}12481249GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {1250ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1251ERR_FAIL_NULL_V(particles_collision, 0);1252ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, 0);12531254if (particles_collision->heightfield_texture == 0) {1255//create1256const int resolutions[RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX] = { 256, 512, 1024, 2048, 4096, 8192 };1257Size2i size;1258if (particles_collision->extents.x > particles_collision->extents.z) {1259size.x = resolutions[particles_collision->heightfield_resolution];1260size.y = int32_t(particles_collision->extents.z / particles_collision->extents.x * size.x);1261} else {1262size.y = resolutions[particles_collision->heightfield_resolution];1263size.x = int32_t(particles_collision->extents.x / particles_collision->extents.z * size.y);1264}12651266glGenTextures(1, &particles_collision->heightfield_texture);1267glActiveTexture(GL_TEXTURE0);1268glBindTexture(GL_TEXTURE_2D, particles_collision->heightfield_texture);1269glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, size.x, size.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);12701271glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);1272glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);1273glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);1274glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);1275glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);1276glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);12771278glGenFramebuffers(1, &particles_collision->heightfield_fb);1279glBindFramebuffer(GL_FRAMEBUFFER, particles_collision->heightfield_fb);1280glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, particles_collision->heightfield_texture, 0);1281#ifdef DEBUG_ENABLED1282GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);1283if (status != GL_FRAMEBUFFER_COMPLETE) {1284WARN_PRINT("Could not create heightmap texture, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));1285}1286#endif1287GLES3::Utilities::get_singleton()->texture_allocated_data(particles_collision->heightfield_texture, size.x * size.y * 4, "Particles collision heightfield texture");12881289particles_collision->heightfield_fb_size = size;12901291glBindTexture(GL_TEXTURE_2D, 0);1292glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);1293}12941295return particles_collision->heightfield_fb;1296}12971298void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) {1299ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1300ERR_FAIL_NULL(particles_collision);13011302if (p_type == particles_collision->type) {1303return;1304}13051306if (particles_collision->heightfield_texture != 0) {1307GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);1308particles_collision->heightfield_texture = 0;1309glDeleteFramebuffers(1, &particles_collision->heightfield_fb);1310particles_collision->heightfield_fb = 0;1311}13121313particles_collision->type = p_type;1314particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);1315}13161317void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) {1318ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1319ERR_FAIL_NULL(particles_collision);1320particles_collision->cull_mask = p_cull_mask;1321particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_CULL_MASK);1322}13231324uint32_t ParticlesStorage::particles_collision_get_cull_mask(RID p_particles_collision) const {1325ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1326ERR_FAIL_NULL_V(particles_collision, 0);1327return particles_collision->cull_mask;1328}13291330void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {1331ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1332ERR_FAIL_NULL(particles_collision);13331334particles_collision->radius = p_radius;1335particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);1336}13371338void ParticlesStorage::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) {1339ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1340ERR_FAIL_NULL(particles_collision);13411342particles_collision->extents = p_extents;1343particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);1344}13451346void ParticlesStorage::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) {1347ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1348ERR_FAIL_NULL(particles_collision);13491350particles_collision->attractor_strength = p_strength;1351}13521353void ParticlesStorage::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) {1354ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1355ERR_FAIL_NULL(particles_collision);13561357particles_collision->attractor_directionality = p_directionality;1358}13591360void ParticlesStorage::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) {1361ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1362ERR_FAIL_NULL(particles_collision);13631364particles_collision->attractor_attenuation = p_curve;1365}13661367void ParticlesStorage::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) {1368WARN_PRINT_ONCE_ED("The Compatibility renderer does not support SDF collisions in 3D particle shaders");1369}13701371void ParticlesStorage::particles_collision_height_field_update(RID p_particles_collision) {1372ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1373ERR_FAIL_NULL(particles_collision);1374particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);1375}13761377void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {1378ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1379ERR_FAIL_NULL(particles_collision);1380ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);13811382if (particles_collision->heightfield_resolution == p_resolution) {1383return;1384}13851386particles_collision->heightfield_resolution = p_resolution;13871388if (particles_collision->heightfield_texture != 0) {1389GLES3::Utilities::get_singleton()->texture_free_data(particles_collision->heightfield_texture);1390particles_collision->heightfield_texture = 0;1391glDeleteFramebuffers(1, &particles_collision->heightfield_fb);1392particles_collision->heightfield_fb = 0;1393}1394}13951396AABB ParticlesStorage::particles_collision_get_aabb(RID p_particles_collision) const {1397ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1398ERR_FAIL_NULL_V(particles_collision, AABB());13991400switch (particles_collision->type) {1401case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT:1402case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: {1403AABB aabb;1404aabb.position = -Vector3(1, 1, 1) * particles_collision->radius;1405aabb.size = Vector3(2, 2, 2) * particles_collision->radius;1406return aabb;1407}1408default: {1409AABB aabb;1410aabb.position = -particles_collision->extents;1411aabb.size = particles_collision->extents * 2;1412return aabb;1413}1414}1415}14161417Vector3 ParticlesStorage::particles_collision_get_extents(RID p_particles_collision) const {1418const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1419ERR_FAIL_NULL_V(particles_collision, Vector3());1420return particles_collision->extents;1421}14221423bool ParticlesStorage::particles_collision_is_heightfield(RID p_particles_collision) const {1424const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1425ERR_FAIL_NULL_V(particles_collision, false);1426return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE;1427}14281429uint32_t ParticlesStorage::particles_collision_get_height_field_mask(RID p_particles_collision) const {1430const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1431ERR_FAIL_NULL_V(particles_collision, false);1432return particles_collision->heightfield_mask;1433}14341435void ParticlesStorage::particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) {1436ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);1437ERR_FAIL_NULL(particles_collision);1438particles_collision->heightfield_mask = p_heightfield_mask;1439}14401441Dependency *ParticlesStorage::particles_collision_get_dependency(RID p_particles_collision) const {1442ParticlesCollision *pc = particles_collision_owner.get_or_null(p_particles_collision);1443ERR_FAIL_NULL_V(pc, nullptr);14441445return &pc->dependency;1446}14471448/* Particles collision instance */14491450RID ParticlesStorage::particles_collision_instance_create(RID p_collision) {1451ParticlesCollisionInstance pci;1452pci.collision = p_collision;1453return particles_collision_instance_owner.make_rid(pci);1454}14551456void ParticlesStorage::particles_collision_instance_free(RID p_rid) {1457particles_collision_instance_owner.free(p_rid);1458}14591460void ParticlesStorage::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {1461ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);1462ERR_FAIL_NULL(pci);1463pci->transform = p_transform;1464}14651466void ParticlesStorage::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) {1467ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);1468ERR_FAIL_NULL(pci);1469pci->active = p_active;1470}14711472#endif // GLES3_ENABLED147314741475