Skip to content
Draft
Show file tree
Hide file tree
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
7 changes: 6 additions & 1 deletion doc/classes/CPUParticles2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@
</methods>
<members>
<member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
Number of particles emitted in one emission cycle.
The number of particles to emit in one emission cycle. The effective emission rate is [code](amount * amount_ratio) / lifetime[/code] particles per second. Higher values will increase processing load, even if not all particles are visible at a given time or if [member amount_ratio] is decreased.
[b]Note:[/b] Changing this value will cause the particle system to restart. To avoid this, change [member amount_ratio] instead.
</member>
<member name="amount_ratio" type="float" setter="set_amount_ratio" getter="get_amount_ratio" default="1.0">
The ratio of particles that should actually be emitted. If set to a value lower than [code]1.0[/code], this will set the amount of emitted particles throughout the lifetime to [code]amount * amount_ratio[/code]. Unlike changing [member amount], changing [member amount_ratio] while emitting does not affect already-emitted particles and doesn't cause the particle system to restart. [member amount_ratio] can be used to create effects that make the number of emitted particles vary over time.
[b]Note:[/b] Reducing the [member amount_ratio] has no performance benefit, since resources need to be allocated and processed for the total [member amount] of particles regardless of the [member amount_ratio]. If you don't intend to change the number of particles emitted while the particles are emitting, make sure [member amount_ratio] is set to [code]1[/code] and change [member amount] to your liking instead.
</member>
<member name="angle_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Each particle's rotation will be animated along this [Curve]. Should be a unit [Curve].
Expand Down
7 changes: 6 additions & 1 deletion doc/classes/CPUParticles3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,12 @@
</methods>
<members>
<member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
Number of particles emitted in one emission cycle.
The number of particles to emit in one emission cycle. The effective emission rate is [code](amount * amount_ratio) / lifetime[/code] particles per second. Higher values will increase processing load, even if not all particles are visible at a given time or if [member amount_ratio] is decreased.
[b]Note:[/b] Changing this value will cause the particle system to restart. To avoid this, change [member amount_ratio] instead.
</member>
<member name="amount_ratio" type="float" setter="set_amount_ratio" getter="get_amount_ratio" default="1.0">
The ratio of particles that should actually be emitted. If set to a value lower than [code]1.0[/code], this will set the amount of emitted particles throughout the lifetime to [code]amount * amount_ratio[/code]. Unlike changing [member amount], changing [member amount_ratio] while emitting does not affect already-emitted particles and doesn't cause the particle system to restart. [member amount_ratio] can be used to create effects that make the number of emitted particles vary over time.
[b]Note:[/b] Reducing the [member amount_ratio] has no performance benefit, since resources need to be allocated and processed for the total [member amount] of particles regardless of the [member amount_ratio]. If you don't intend to change the number of particles emitted while the particles are emitting, make sure [member amount_ratio] is set to [code]1[/code] and change [member amount] to your liking instead.
</member>
<member name="angle_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Each particle's rotation will be animated along this [Curve]. Should be a unit [Curve].
Expand Down
28 changes: 28 additions & 0 deletions scene/2d/cpu_particles_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ void CPUParticles2D::set_amount(int p_amount) {
RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true);

particle_order.resize(p_amount);
set_amount_ratio(amount_ratio);
}

void CPUParticles2D::set_amount_ratio(float p_amount_ratio) {
amount_ratio = p_amount_ratio;
}

void CPUParticles2D::set_lifetime(double p_lifetime) {
Expand Down Expand Up @@ -138,6 +143,10 @@ int CPUParticles2D::get_amount() const {
return particles.size();
}

float CPUParticles2D::get_amount_ratio() const {
return amount_ratio;
}

double CPUParticles2D::get_lifetime() const {
return lifetime;
}
Expand Down Expand Up @@ -771,12 +780,22 @@ void CPUParticles2D::_particles_process(double p_delta) {
velocity_xform[2] = Vector2();
}

float amount_ratio_accumulator = 0.0;
double system_phase = time / lifetime;

bool should_be_active = false;
for (int i = 0; i < pcount; i++) {
Particle &p = parray[i];

amount_ratio_accumulator += amount_ratio;
bool active_by_ratio = false;
if (amount_ratio_accumulator >= 1.0) {
active_by_ratio = true;
amount_ratio_accumulator -= 1.0;
} else if (!p.active) {
Copy link
Member

@KoBeWi KoBeWi Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same condition is few lines below.

continue;
}

if (!emitting && !p.active) {
continue;
}
Expand Down Expand Up @@ -835,6 +854,11 @@ void CPUParticles2D::_particles_process(double p_delta) {
float tv = 0.0;

if (restart) {
if (!active_by_ratio) {
p.active = false;
continue;
}

if (!emitting) {
p.active = false;
continue;
Expand Down Expand Up @@ -1415,6 +1439,7 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles2D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles2D::set_amount);
ClassDB::bind_method(D_METHOD("set_amount_ratio", "amount_ratio"), &CPUParticles2D::set_amount_ratio);
ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles2D::set_lifetime);
ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles2D::set_one_shot);
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles2D::set_pre_process_time);
Expand All @@ -1429,6 +1454,7 @@ void CPUParticles2D::_bind_methods() {

ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles2D::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles2D::get_amount);
ClassDB::bind_method(D_METHOD("get_amount_ratio"), &CPUParticles2D::get_amount_ratio);
ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles2D::get_lifetime);
ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles2D::get_one_shot);
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles2D::get_pre_process_time);
Expand Down Expand Up @@ -1456,6 +1482,7 @@ void CPUParticles2D::_bind_methods() {

ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); // FIXME: Evaluate support for `exp` in integer properties, or remove this.
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_amount_ratio", "get_amount_ratio");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime");
Expand Down Expand Up @@ -1647,6 +1674,7 @@ CPUParticles2D::CPUParticles2D() {

set_emitting(true);
set_amount(8);
set_amount_ratio(1);
set_use_local_coordinates(false);
set_seed(Math::rand());

Expand Down
3 changes: 3 additions & 0 deletions scene/2d/cpu_particles_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class CPUParticles2D : public Node2D {

bool one_shot = false;

float amount_ratio = 1;
double lifetime = 1.0;
double pre_process_time = 0.0;
double _requested_process_time = 0.0;
Expand Down Expand Up @@ -228,6 +229,7 @@ class CPUParticles2D : public Node2D {
public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
void set_amount_ratio(float p_amount_ratio);
void set_lifetime(double p_lifetime);
void set_one_shot(bool p_one_shot);
void set_pre_process_time(double p_time);
Expand All @@ -239,6 +241,7 @@ class CPUParticles2D : public Node2D {

bool is_emitting() const;
int get_amount() const;
float get_amount_ratio() const;
double get_lifetime() const;
bool get_one_shot() const;
double get_pre_process_time() const;
Expand Down
28 changes: 28 additions & 0 deletions scene/3d/cpu_particles_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ void CPUParticles3D::set_amount(int p_amount) {
RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_3D, true, true);

particle_order.resize(p_amount);
set_amount_ratio(amount_ratio);
}

void CPUParticles3D::set_amount_ratio(float p_amount_ratio) {
amount_ratio = p_amount_ratio;
}

void CPUParticles3D::set_lifetime(double p_lifetime) {
Expand Down Expand Up @@ -134,6 +139,10 @@ int CPUParticles3D::get_amount() const {
return particles.size();
}

float CPUParticles3D::get_amount_ratio() const {
return amount_ratio;
}

double CPUParticles3D::get_lifetime() const {
return lifetime;
}
Expand Down Expand Up @@ -742,12 +751,22 @@ void CPUParticles3D::_particles_process(double p_delta) {
velocity_xform = emission_xform.basis;
}

float amount_ratio_accumulator = 0.0;
double system_phase = time / lifetime;

bool should_be_active = false;
for (int i = 0; i < pcount; i++) {
Particle &p = parray[i];

amount_ratio_accumulator += amount_ratio;
bool active_by_ratio = false;
if (amount_ratio_accumulator >= 1.0) {
active_by_ratio = true;
amount_ratio_accumulator -= 1.0;
} else if (!p.active) {
continue;
}

if (!emitting && !p.active) {
continue;
}
Expand Down Expand Up @@ -806,6 +825,11 @@ void CPUParticles3D::_particles_process(double p_delta) {
float tv = 0.0;

if (restart) {
if (!active_by_ratio) {
p.active = false;
continue;
}

if (!emitting) {
p.active = false;
continue;
Expand Down Expand Up @@ -1504,6 +1528,7 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles3D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles3D::set_amount);
ClassDB::bind_method(D_METHOD("set_amount_ratio", "amount_ratio"), &CPUParticles3D::set_amount_ratio);
ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles3D::set_lifetime);
ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles3D::set_one_shot);
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles3D::set_pre_process_time);
Expand All @@ -1518,6 +1543,7 @@ void CPUParticles3D::_bind_methods() {

ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles3D::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles3D::get_amount);
ClassDB::bind_method(D_METHOD("get_amount_ratio"), &CPUParticles3D::get_amount_ratio);
ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles3D::get_lifetime);
ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles3D::get_one_shot);
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles3D::get_pre_process_time);
Expand Down Expand Up @@ -1549,6 +1575,7 @@ void CPUParticles3D::_bind_methods() {

ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); // FIXME: Evaluate support for `exp` in integer properties, or remove this.
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_amount_ratio", "get_amount_ratio");
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
Expand Down Expand Up @@ -1774,6 +1801,7 @@ CPUParticles3D::CPUParticles3D() {

set_emitting(true);
set_amount(8);
set_amount_ratio(1);
set_seed(Math::rand());

rng.instantiate();
Expand Down
3 changes: 3 additions & 0 deletions scene/3d/cpu_particles_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class CPUParticles3D : public GeometryInstance3D {

bool one_shot = false;

float amount_ratio = 1;
double lifetime = 1.0;
double pre_process_time = 0.0;
double _requested_process_time = 0.0;
Expand Down Expand Up @@ -219,6 +220,7 @@ class CPUParticles3D : public GeometryInstance3D {

void set_emitting(bool p_emitting);
void set_amount(int p_amount);
void set_amount_ratio(float p_amount_ratio);
void set_lifetime(double p_lifetime);
void set_one_shot(bool p_one_shot);
void set_pre_process_time(double p_time);
Expand All @@ -231,6 +233,7 @@ class CPUParticles3D : public GeometryInstance3D {

bool is_emitting() const;
int get_amount() const;
float get_amount_ratio() const;
double get_lifetime() const;
bool get_one_shot() const;
double get_pre_process_time() const;
Expand Down
Loading