From eb5839dcbb78d166e4612d2c72c8a7eb0d8da8b0 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Wed, 4 Dec 2024 12:26:41 -0300 Subject: [PATCH] Add "At Start" mode for sub-emitter particles --- doc/classes/ParticleProcessMaterial.xml | 8 ++++- scene/resources/particle_process_material.cpp | 34 ++++++++++++++++++- scene/resources/particle_process_material.h | 8 ++++- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml index 742e0cc44cf..44bd0ac5644 100644 --- a/doc/classes/ParticleProcessMaterial.xml +++ b/doc/classes/ParticleProcessMaterial.xml @@ -346,6 +346,10 @@ The amount of particles to spawn from the subemitter node when the particle expires. [b]Note:[/b] This value shouldn't exceed [member GPUParticles2D.amount] or [member GPUParticles3D.amount] defined on the [i]subemitter node[/i] (not the main node), relative to the subemitter's particle lifetime. If the number of particles is exceeded, no new particles will spawn from the subemitter until enough particles have expired. + + The amount of particles to spawn from the subemitter node when the particle spawns. + [b]Note:[/b] This value shouldn't exceed [member GPUParticles2D.amount] or [member GPUParticles3D.amount] defined on the [i]subemitter node[/i] (not the main node), relative to the subemitter's particle lifetime. If the number of particles is exceeded, no new particles will spawn from the subemitter until enough particles have expired. + The frequency at which particles should be emitted from the subemitter node. One particle will be spawned every [member sub_emitter_frequency] seconds. [b]Note:[/b] This value shouldn't exceed [member GPUParticles2D.amount] or [member GPUParticles3D.amount] defined on the [i]subemitter node[/i] (not the main node), relative to the subemitter's particle lifetime. If the number of particles is exceeded, no new particles will spawn from the subemitter until enough particles have expired. @@ -514,7 +518,9 @@ - + + + Represents the size of the [enum SubEmitterMode] enum. diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp index 09bc1fa8e42..2a599d537ab 100644 --- a/scene/resources/particle_process_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -132,6 +132,7 @@ void ParticleProcessMaterial::init_shaders() { shader_names->sub_emitter_frequency = "sub_emitter_frequency"; shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end"; shader_names->sub_emitter_amount_at_collision = "sub_emitter_amount_at_collision"; + shader_names->sub_emitter_amount_at_start = "sub_emitter_amount_at_start"; shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity"; shader_names->collision_friction = "collision_friction"; @@ -287,6 +288,9 @@ void ParticleProcessMaterial::_update_shader() { if (sub_emitter_mode == SUB_EMITTER_AT_COLLISION) { code += "uniform int sub_emitter_amount_at_collision;\n"; } + if (sub_emitter_mode == SUB_EMITTER_AT_START) { + code += "uniform int sub_emitter_amount_at_start;\n"; + } code += "uniform bool sub_emitter_keep_velocity;\n"; } @@ -918,6 +922,10 @@ void ParticleProcessMaterial::_update_shader() { code += " float pi = 3.14159;\n"; code += " float degree_to_rad = pi / 180.0;\n\n"; + if (sub_emitter_mode == SUB_EMITTER_AT_START && !RenderingServer::get_singleton()->is_low_end()) { + code += " bool just_spawned = CUSTOM.y == 0.0;\n"; + } + code += " CUSTOM.y += DELTA / LIFETIME;\n"; code += " CUSTOM.y = mix(CUSTOM.y, 1.0, INTERPOLATE_TO_END);\n"; code += " float lifetime_percent = CUSTOM.y / params.lifetime;\n"; @@ -1134,6 +1142,11 @@ void ParticleProcessMaterial::_update_shader() { code += " emit_count = sub_emitter_amount_at_end;\n"; code += " }\n"; } break; + case SUB_EMITTER_AT_START: { + code += " if (just_spawned) {\n"; + code += " emit_count = sub_emitter_amount_at_start;\n"; + code += " }\n"; + } break; default: { } } @@ -1819,6 +1832,10 @@ void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const p_property.usage = PROPERTY_USAGE_NONE; } + if (p_property.name == "sub_emitter_amount_at_start" && sub_emitter_mode != SUB_EMITTER_AT_START) { + p_property.usage = PROPERTY_USAGE_NONE; + } + if (!turbulence_enabled) { if (p_property.name == "turbulence_noise_strength" || p_property.name == "turbulence_noise_scale" || @@ -1893,6 +1910,15 @@ int ParticleProcessMaterial::get_sub_emitter_amount_at_collision() const { return sub_emitter_amount_at_collision; } +void ParticleProcessMaterial::set_sub_emitter_amount_at_start(int p_amount) { + sub_emitter_amount_at_start = p_amount; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_start, p_amount); +} + +int ParticleProcessMaterial::get_sub_emitter_amount_at_start() const { + return sub_emitter_amount_at_start; +} + void ParticleProcessMaterial::set_sub_emitter_keep_velocity(bool p_enable) { sub_emitter_keep_velocity = p_enable; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable); @@ -2074,6 +2100,9 @@ void ParticleProcessMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_collision"), &ParticleProcessMaterial::get_sub_emitter_amount_at_collision); ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_collision", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_collision); + ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_start"), &ParticleProcessMaterial::get_sub_emitter_amount_at_start); + ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_start", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_start); + ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity); ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity); @@ -2203,10 +2232,11 @@ void ParticleProcessMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_scale"), "set_collision_use_scale", "is_collision_using_scale"); ADD_GROUP("Sub Emitter", "sub_emitter_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled:0,Constant:1,At Start:4,At End:2,At Collision:3"), "set_sub_emitter_mode", "get_sub_emitter_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_collision", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_collision", "get_sub_emitter_amount_at_collision"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_start", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_start", "get_sub_emitter_amount_at_start"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity"); BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); @@ -2249,6 +2279,7 @@ void ParticleProcessMaterial::_bind_methods() { BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT); BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END); BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION); + BIND_ENUM_CONSTANT(SUB_EMITTER_AT_START); BIND_ENUM_CONSTANT(SUB_EMITTER_MAX); BIND_ENUM_CONSTANT(COLLISION_DISABLED); @@ -2320,6 +2351,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() : set_sub_emitter_frequency(4); set_sub_emitter_amount_at_end(1); set_sub_emitter_amount_at_collision(1); + set_sub_emitter_amount_at_start(1); set_sub_emitter_keep_velocity(false); set_attractor_interaction_enabled(true); diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h index 12e3fbb64e4..30bf9fc313f 100644 --- a/scene/resources/particle_process_material.h +++ b/scene/resources/particle_process_material.h @@ -96,6 +96,7 @@ public: SUB_EMITTER_CONSTANT, SUB_EMITTER_AT_END, SUB_EMITTER_AT_COLLISION, + SUB_EMITTER_AT_START, SUB_EMITTER_MAX }; @@ -117,7 +118,7 @@ private: uint64_t emission_shape : 3; uint64_t invalid_key : 1; uint64_t has_emission_color : 1; - uint64_t sub_emitter : 2; + uint64_t sub_emitter : 3; uint64_t attractor_enabled : 1; uint64_t collision_mode : 2; uint64_t collision_scale : 1; @@ -282,6 +283,7 @@ private: StringName sub_emitter_frequency; StringName sub_emitter_amount_at_end; StringName sub_emitter_amount_at_collision; + StringName sub_emitter_amount_at_start; StringName sub_emitter_keep_velocity; StringName collision_friction; @@ -349,6 +351,7 @@ private: double sub_emitter_frequency = 0.0; int sub_emitter_amount_at_end = 0; int sub_emitter_amount_at_collision = 0; + int sub_emitter_amount_at_start = 0; bool sub_emitter_keep_velocity = false; //do not save emission points here @@ -487,6 +490,9 @@ public: void set_sub_emitter_amount_at_collision(int p_amount); int get_sub_emitter_amount_at_collision() const; + void set_sub_emitter_amount_at_start(int p_amount); + int get_sub_emitter_amount_at_start() const; + void set_sub_emitter_keep_velocity(bool p_enable); bool get_sub_emitter_keep_velocity() const;