Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "At Start" mode for sub-emitter particles #100050

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion doc/classes/ParticleProcessMaterial.xml
Original file line number Diff line number Diff line change
@@ -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.
@@ -514,7 +518,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">
34 changes: 33 additions & 1 deletion scene/resources/particle_process_material.cpp
Original file line number Diff line number Diff line change
@@ -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);
8 changes: 7 additions & 1 deletion scene/resources/particle_process_material.h
Original file line number Diff line number Diff line change
@@ -96,6 +96,7 @@ class ParticleProcessMaterial : public Material {
SUB_EMITTER_CONSTANT,
SUB_EMITTER_AT_END,
SUB_EMITTER_AT_COLLISION,
SUB_EMITTER_AT_START,
SUB_EMITTER_MAX
};

@@ -117,7 +118,7 @@ class ParticleProcessMaterial : public Material {
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 @@ class ParticleProcessMaterial : public Material {
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 @@ class ParticleProcessMaterial : public Material {
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 @@ class ParticleProcessMaterial : public Material {
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;