Merge pull request #100050 from YeldhamDev/sub_emitter_at_start

Add "At Start" mode for sub-emitter particles
This commit is contained in:
Rémi Verschelde 2025-01-14 18:29:20 +01:00
commit 1e1f54e954
3 changed files with 47 additions and 3 deletions

View file

@ -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.
</member>
<member name="sub_emitter_amount_at_start" type="int" setter="set_sub_emitter_amount_at_start" getter="get_sub_emitter_amount_at_start">
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.
</member>
<member name="sub_emitter_frequency" type="float" setter="set_sub_emitter_frequency" getter="get_sub_emitter_frequency">
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.
@ -521,7 +525,9 @@
</constant>
<constant name="SUB_EMITTER_AT_COLLISION" value="3" enum="SubEmitterMode">
</constant>
<constant name="SUB_EMITTER_MAX" value="4" enum="SubEmitterMode">
<constant name="SUB_EMITTER_AT_START" value="4" enum="SubEmitterMode">
</constant>
<constant name="SUB_EMITTER_MAX" value="5" enum="SubEmitterMode">
Represents the size of the [enum SubEmitterMode] enum.
</constant>
<constant name="COLLISION_DISABLED" value="0" enum="CollisionMode">

View file

@ -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";
}
@ -923,6 +927,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";
@ -1139,6 +1147,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: {
}
}
@ -1858,6 +1871,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" ||
@ -1932,6 +1949,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);
@ -2113,6 +2139,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);
@ -2242,10 +2271,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");
ADD_SIGNAL(MethodInfo("emission_shape_changed"));
@ -2290,6 +2320,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);
@ -2361,6 +2392,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);

View file

@ -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;