Merge pull request #81559 from matorin57/3.x-backport-finished-singal-GPU-particles
[3.x] Backport "Add `finished` signal to GPUParticles"
This commit is contained in:
commit
862d63e9f7
8 changed files with 132 additions and 15 deletions
|
@ -105,6 +105,14 @@
|
||||||
[b]Note:[/b] If the [ParticlesMaterial] in use is configured to cast shadows, you may want to enlarge this AABB to ensure the shadow is updated when particles are off-screen.
|
[b]Note:[/b] If the [ParticlesMaterial] in use is configured to cast shadows, you may want to enlarge this AABB to ensure the shadow is updated when particles are off-screen.
|
||||||
</member>
|
</member>
|
||||||
</members>
|
</members>
|
||||||
|
<signals>
|
||||||
|
<signal name="finished">
|
||||||
|
<description>
|
||||||
|
Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
|
||||||
|
[b]Note:[/b] Due to the particles being computed on the GPU there might be a delay before the signal gets emitted.
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
|
</signals>
|
||||||
<constants>
|
<constants>
|
||||||
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
|
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
|
||||||
Particles are drawn in the order emitted.
|
Particles are drawn in the order emitted.
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<return type="Rect2" />
|
<return type="Rect2" />
|
||||||
<description>
|
<description>
|
||||||
Returns a rectangle containing the positions of all existing particles.
|
Returns a rectangle containing the positions of all existing particles.
|
||||||
|
[b]Note:[/b] When using threaded rendering this method synchronizes the rendering thread. Calling it often may have a negative impact on performance.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="restart">
|
<method name="restart">
|
||||||
|
@ -83,6 +84,14 @@
|
||||||
Grow the rect if particles suddenly appear/disappear when the node enters/exits the screen. The [Rect2] can be grown via code or with the [b]Particles → Generate Visibility Rect[/b] editor tool.
|
Grow the rect if particles suddenly appear/disappear when the node enters/exits the screen. The [Rect2] can be grown via code or with the [b]Particles → Generate Visibility Rect[/b] editor tool.
|
||||||
</member>
|
</member>
|
||||||
</members>
|
</members>
|
||||||
|
<signals>
|
||||||
|
<signal name="finished">
|
||||||
|
<description>
|
||||||
|
Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
|
||||||
|
[b]Note:[/b] Due to the particles being computed on the GPU there might be a delay before the signal gets emitted.
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
|
</signals>
|
||||||
<constants>
|
<constants>
|
||||||
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
|
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
|
||||||
Particles are drawn in the order emitted.
|
Particles are drawn in the order emitted.
|
||||||
|
|
|
@ -39,13 +39,30 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Particles2D::set_emitting(bool p_emitting) {
|
void Particles2D::set_emitting(bool p_emitting) {
|
||||||
VS::get_singleton()->particles_set_emitting(particles, p_emitting);
|
// Do not return even if `p_emitting == emitting` because `emitting` is just an approximation.
|
||||||
|
|
||||||
if (p_emitting && one_shot) {
|
if (p_emitting && one_shot) {
|
||||||
|
if (!active && !emitting) {
|
||||||
|
// Last cycle ended.
|
||||||
|
active = true;
|
||||||
|
time = 0;
|
||||||
|
signal_canceled = false;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
} else {
|
||||||
|
signal_canceled = true;
|
||||||
|
}
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
} else if (!p_emitting) {
|
} else if (!p_emitting) {
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
} else {
|
||||||
set_process_internal(false);
|
set_process_internal(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitting = p_emitting;
|
||||||
|
VS::get_singleton()->particles_set_emitting(particles, p_emitting);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particles2D::set_amount(int p_amount) {
|
void Particles2D::set_amount(int p_amount) {
|
||||||
|
@ -148,7 +165,7 @@ void Particles2D::set_show_visibility_rect(bool p_show_visibility_rect) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool Particles2D::is_emitting() const {
|
bool Particles2D::is_emitting() const {
|
||||||
return VS::get_singleton()->particles_get_emitting(particles);
|
return emitting;
|
||||||
}
|
}
|
||||||
int Particles2D::get_amount() const {
|
int Particles2D::get_amount() const {
|
||||||
return amount;
|
return amount;
|
||||||
|
@ -287,6 +304,16 @@ void Particles2D::_validate_property(PropertyInfo &property) const {
|
||||||
void Particles2D::restart() {
|
void Particles2D::restart() {
|
||||||
VS::get_singleton()->particles_restart(particles);
|
VS::get_singleton()->particles_restart(particles);
|
||||||
VS::get_singleton()->particles_set_emitting(particles, true);
|
VS::get_singleton()->particles_set_emitting(particles, true);
|
||||||
|
|
||||||
|
emitting = true;
|
||||||
|
active = true;
|
||||||
|
signal_canceled = false;
|
||||||
|
time = 0;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particles2D::_notification(int p_what) {
|
void Particles2D::_notification(int p_what) {
|
||||||
|
@ -322,11 +349,25 @@ void Particles2D::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
|
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
|
||||||
if (one_shot && !is_emitting()) {
|
if (one_shot) {
|
||||||
_change_notify();
|
time += get_process_delta_time();
|
||||||
|
if (time > emission_time) {
|
||||||
|
emitting = false;
|
||||||
|
if (!active) {
|
||||||
set_process_internal(false);
|
set_process_internal(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (time > active_time) {
|
||||||
|
if (active && !signal_canceled) {
|
||||||
|
emit_signal(SceneStringNames::get_singleton()->finished);
|
||||||
|
}
|
||||||
|
active = false;
|
||||||
|
if (!emitting) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particles2D::_bind_methods() {
|
void Particles2D::_bind_methods() {
|
||||||
|
@ -371,6 +412,8 @@ void Particles2D::_bind_methods() {
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
|
ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
|
||||||
|
|
||||||
|
ADD_SIGNAL(MethodInfo("finished"));
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
|
||||||
ADD_GROUP("Time", "");
|
ADD_GROUP("Time", "");
|
||||||
|
|
|
@ -48,7 +48,10 @@ public:
|
||||||
private:
|
private:
|
||||||
RID particles;
|
RID particles;
|
||||||
|
|
||||||
bool one_shot;
|
bool emitting = false;
|
||||||
|
bool active = false;
|
||||||
|
bool signal_canceled = false;
|
||||||
|
bool one_shot = false;
|
||||||
int amount;
|
int amount;
|
||||||
float lifetime;
|
float lifetime;
|
||||||
float pre_process_time;
|
float pre_process_time;
|
||||||
|
@ -73,6 +76,10 @@ private:
|
||||||
|
|
||||||
void _update_particle_emission_transform();
|
void _update_particle_emission_transform();
|
||||||
|
|
||||||
|
double time = 0.0;
|
||||||
|
double emission_time = 0.0;
|
||||||
|
double active_time = 0.0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
virtual void _validate_property(PropertyInfo &property) const;
|
virtual void _validate_property(PropertyInfo &property) const;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
#include "scene/resources/particles_material.h"
|
#include "scene/resources/particles_material.h"
|
||||||
|
#include "scene/scene_string_names.h"
|
||||||
|
|
||||||
#include "servers/visual_server.h"
|
#include "servers/visual_server.h"
|
||||||
|
|
||||||
|
@ -43,13 +44,31 @@ PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particles::set_emitting(bool p_emitting) {
|
void Particles::set_emitting(bool p_emitting) {
|
||||||
VS::get_singleton()->particles_set_emitting(particles, p_emitting);
|
// Do not return even if `p_emitting == emitting` because `emitting` is just an approximation.
|
||||||
|
|
||||||
if (p_emitting && one_shot) {
|
if (p_emitting && one_shot) {
|
||||||
|
if (!active && !emitting) {
|
||||||
|
// Last cycle ended.
|
||||||
|
active = true;
|
||||||
|
time = 0;
|
||||||
|
signal_canceled = false;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
} else {
|
||||||
|
signal_canceled = true;
|
||||||
|
}
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
} else if (!p_emitting) {
|
} else if (!p_emitting) {
|
||||||
set_process_internal(false);
|
set_process_internal(false);
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
} else {
|
||||||
|
set_process_internal(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitting = p_emitting;
|
||||||
|
VS::get_singleton()->particles_set_emitting(particles, p_emitting);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Particles::set_amount(int p_amount) {
|
void Particles::set_amount(int p_amount) {
|
||||||
|
@ -118,7 +137,7 @@ void Particles::set_speed_scale(float p_scale) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Particles::is_emitting() const {
|
bool Particles::is_emitting() const {
|
||||||
return VS::get_singleton()->particles_get_emitting(particles);
|
return emitting;
|
||||||
}
|
}
|
||||||
int Particles::get_amount() const {
|
int Particles::get_amount() const {
|
||||||
return amount;
|
return amount;
|
||||||
|
@ -281,6 +300,16 @@ String Particles::get_configuration_warning() const {
|
||||||
void Particles::restart() {
|
void Particles::restart() {
|
||||||
VisualServer::get_singleton()->particles_restart(particles);
|
VisualServer::get_singleton()->particles_restart(particles);
|
||||||
VisualServer::get_singleton()->particles_set_emitting(particles, true);
|
VisualServer::get_singleton()->particles_set_emitting(particles, true);
|
||||||
|
|
||||||
|
emitting = true;
|
||||||
|
active = true;
|
||||||
|
signal_canceled = false;
|
||||||
|
time = 0;
|
||||||
|
emission_time = lifetime * (1 - explosiveness_ratio);
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AABB Particles::capture_aabb() const {
|
AABB Particles::capture_aabb() const {
|
||||||
|
@ -309,11 +338,25 @@ void Particles::_notification(int p_what) {
|
||||||
// Use internal process when emitting and one_shot are on so that when
|
// Use internal process when emitting and one_shot are on so that when
|
||||||
// the shot ends the editor can properly update
|
// the shot ends the editor can properly update
|
||||||
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
|
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
|
||||||
if (one_shot && !is_emitting()) {
|
if (one_shot) {
|
||||||
_change_notify();
|
time += get_process_delta_time();
|
||||||
|
if (time > emission_time) {
|
||||||
|
emitting = false;
|
||||||
|
if (!active) {
|
||||||
set_process_internal(false);
|
set_process_internal(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (time > active_time) {
|
||||||
|
if (active && !signal_canceled) {
|
||||||
|
emit_signal(SceneStringNames::get_singleton()->finished);
|
||||||
|
}
|
||||||
|
active = false;
|
||||||
|
if (!emitting) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
|
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
|
||||||
// make sure particles are updated before rendering occurs if they were active before
|
// make sure particles are updated before rendering occurs if they were active before
|
||||||
|
@ -365,6 +408,8 @@ void Particles::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("restart"), &Particles::restart);
|
ClassDB::bind_method(D_METHOD("restart"), &Particles::restart);
|
||||||
ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
|
ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
|
||||||
|
|
||||||
|
ADD_SIGNAL(MethodInfo("finished"));
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
|
||||||
ADD_GROUP("Time", "");
|
ADD_GROUP("Time", "");
|
||||||
|
|
|
@ -53,7 +53,10 @@ public:
|
||||||
private:
|
private:
|
||||||
RID particles;
|
RID particles;
|
||||||
|
|
||||||
bool one_shot;
|
bool emitting = false;
|
||||||
|
bool active = false;
|
||||||
|
bool signal_canceled = false;
|
||||||
|
bool one_shot = false;
|
||||||
int amount;
|
int amount;
|
||||||
float lifetime;
|
float lifetime;
|
||||||
float pre_process_time;
|
float pre_process_time;
|
||||||
|
@ -71,6 +74,10 @@ private:
|
||||||
|
|
||||||
Vector<Ref<Mesh>> draw_passes;
|
Vector<Ref<Mesh>> draw_passes;
|
||||||
|
|
||||||
|
double time = 0.0;
|
||||||
|
double emission_time = 0.0;
|
||||||
|
double active_time = 0.0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
|
@ -61,7 +61,6 @@ SceneStringNames::SceneStringNames() {
|
||||||
finished = StaticCString::create("finished");
|
finished = StaticCString::create("finished");
|
||||||
loop_finished = StaticCString::create("loop_finished");
|
loop_finished = StaticCString::create("loop_finished");
|
||||||
step_finished = StaticCString::create("step_finished");
|
step_finished = StaticCString::create("step_finished");
|
||||||
emission_finished = StaticCString::create("emission_finished");
|
|
||||||
animation_finished = StaticCString::create("animation_finished");
|
animation_finished = StaticCString::create("animation_finished");
|
||||||
animation_changed = StaticCString::create("animation_changed");
|
animation_changed = StaticCString::create("animation_changed");
|
||||||
animation_started = StaticCString::create("animation_started");
|
animation_started = StaticCString::create("animation_started");
|
||||||
|
|
|
@ -93,7 +93,6 @@ public:
|
||||||
StringName finished;
|
StringName finished;
|
||||||
StringName loop_finished;
|
StringName loop_finished;
|
||||||
StringName step_finished;
|
StringName step_finished;
|
||||||
StringName emission_finished;
|
|
||||||
StringName animation_finished;
|
StringName animation_finished;
|
||||||
StringName animation_changed;
|
StringName animation_changed;
|
||||||
StringName animation_started;
|
StringName animation_started;
|
||||||
|
|
Loading…
Reference in a new issue