You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Merge pull request #76859 from HolonProduction/emission-finished-gpu
Add `finished` signal to GPUParticles
This commit is contained in:
@@ -18,6 +18,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="emit_particle">
|
<method name="emit_particle">
|
||||||
@@ -108,6 +109,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.
|
||||||
|
|||||||
@@ -130,6 +130,14 @@
|
|||||||
Grow the box if particles suddenly appear/disappear when the node enters/exits the screen. The [AABB] can be grown via code or with the [b]Particles → Generate AABB[/b] editor tool.
|
Grow the box if particles suddenly appear/disappear when the node enters/exits the screen. The [AABB] can be grown via code or with the [b]Particles → Generate AABB[/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.
|
||||||
|
|||||||
@@ -32,19 +32,37 @@
|
|||||||
|
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
#include "scene/resources/particle_process_material.h"
|
#include "scene/resources/particle_process_material.h"
|
||||||
|
#include "scene/scene_string_names.h"
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
#include "core/config/engine.h"
|
#include "core/config/engine.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void GPUParticles2D::set_emitting(bool p_emitting) {
|
void GPUParticles2D::set_emitting(bool p_emitting) {
|
||||||
RS::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_cancled = false;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
} else {
|
||||||
|
signal_cancled = true;
|
||||||
|
}
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
} else if (!p_emitting) {
|
} else if (!p_emitting) {
|
||||||
set_process_internal(false);
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
} else {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitting = p_emitting;
|
||||||
|
RS::get_singleton()->particles_set_emitting(particles, p_emitting);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUParticles2D::set_amount(int p_amount) {
|
void GPUParticles2D::set_amount(int p_amount) {
|
||||||
@@ -211,7 +229,7 @@ void GPUParticles2D::set_speed_scale(double p_scale) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GPUParticles2D::is_emitting() const {
|
bool GPUParticles2D::is_emitting() const {
|
||||||
return RS::get_singleton()->particles_get_emitting(particles);
|
return emitting;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GPUParticles2D::get_amount() const {
|
int GPUParticles2D::get_amount() const {
|
||||||
@@ -405,6 +423,16 @@ NodePath GPUParticles2D::get_sub_emitter() const {
|
|||||||
void GPUParticles2D::restart() {
|
void GPUParticles2D::restart() {
|
||||||
RS::get_singleton()->particles_restart(particles);
|
RS::get_singleton()->particles_restart(particles);
|
||||||
RS::get_singleton()->particles_set_emitting(particles, true);
|
RS::get_singleton()->particles_set_emitting(particles, true);
|
||||||
|
|
||||||
|
emitting = true;
|
||||||
|
active = true;
|
||||||
|
signal_cancled = false;
|
||||||
|
time = 0;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUParticles2D::_notification(int p_what) {
|
void GPUParticles2D::_notification(int p_what) {
|
||||||
@@ -570,9 +598,23 @@ void GPUParticles2D::_notification(int p_what) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_INTERNAL_PROCESS: {
|
case NOTIFICATION_INTERNAL_PROCESS: {
|
||||||
if (one_shot && !is_emitting()) {
|
if (one_shot) {
|
||||||
notify_property_list_changed();
|
time += get_process_delta_time();
|
||||||
set_process_internal(false);
|
if (time > emission_time) {
|
||||||
|
emitting = false;
|
||||||
|
if (!active) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (time > active_time) {
|
||||||
|
if (active && !signal_cancled) {
|
||||||
|
emit_signal(SceneStringNames::get_singleton()->finished);
|
||||||
|
}
|
||||||
|
active = false;
|
||||||
|
if (!emitting) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@@ -638,6 +680,8 @@ void GPUParticles2D::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("set_trail_section_subdivisions", "subdivisions"), &GPUParticles2D::set_trail_section_subdivisions);
|
ClassDB::bind_method(D_METHOD("set_trail_section_subdivisions", "subdivisions"), &GPUParticles2D::set_trail_section_subdivisions);
|
||||||
ClassDB::bind_method(D_METHOD("get_trail_section_subdivisions"), &GPUParticles2D::get_trail_section_subdivisions);
|
ClassDB::bind_method(D_METHOD("get_trail_section_subdivisions"), &GPUParticles2D::get_trail_section_subdivisions);
|
||||||
|
|
||||||
|
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_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
|
ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
RID particles;
|
RID particles;
|
||||||
|
|
||||||
|
bool emitting = false;
|
||||||
|
bool active = false;
|
||||||
|
bool signal_cancled = false;
|
||||||
bool one_shot = false;
|
bool one_shot = false;
|
||||||
int amount = 0;
|
int amount = 0;
|
||||||
double lifetime = 0.0;
|
double lifetime = 0.0;
|
||||||
@@ -78,6 +81,10 @@ private:
|
|||||||
int trail_sections = 8;
|
int trail_sections = 8;
|
||||||
int trail_section_subdivisions = 4;
|
int trail_section_subdivisions = 4;
|
||||||
|
|
||||||
|
double time = 0.0;
|
||||||
|
double emission_time = 0.0;
|
||||||
|
double active_time = 0.0;
|
||||||
|
|
||||||
RID mesh;
|
RID mesh;
|
||||||
|
|
||||||
void _attach_sub_emitter();
|
void _attach_sub_emitter();
|
||||||
|
|||||||
@@ -31,19 +31,37 @@
|
|||||||
#include "gpu_particles_3d.h"
|
#include "gpu_particles_3d.h"
|
||||||
|
|
||||||
#include "scene/resources/particle_process_material.h"
|
#include "scene/resources/particle_process_material.h"
|
||||||
|
#include "scene/scene_string_names.h"
|
||||||
|
|
||||||
AABB GPUParticles3D::get_aabb() const {
|
AABB GPUParticles3D::get_aabb() const {
|
||||||
return AABB();
|
return AABB();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUParticles3D::set_emitting(bool p_emitting) {
|
void GPUParticles3D::set_emitting(bool p_emitting) {
|
||||||
RS::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_cancled = false;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
} else {
|
||||||
|
signal_cancled = true;
|
||||||
|
}
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
} else if (!p_emitting) {
|
} else if (!p_emitting) {
|
||||||
set_process_internal(false);
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
} else {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitting = p_emitting;
|
||||||
|
RS::get_singleton()->particles_set_emitting(particles, p_emitting);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUParticles3D::set_amount(int p_amount) {
|
void GPUParticles3D::set_amount(int p_amount) {
|
||||||
@@ -122,7 +140,7 @@ void GPUParticles3D::set_collision_base_size(real_t p_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GPUParticles3D::is_emitting() const {
|
bool GPUParticles3D::is_emitting() const {
|
||||||
return RS::get_singleton()->particles_get_emitting(particles);
|
return emitting;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GPUParticles3D::get_amount() const {
|
int GPUParticles3D::get_amount() const {
|
||||||
@@ -373,6 +391,16 @@ PackedStringArray GPUParticles3D::get_configuration_warnings() const {
|
|||||||
void GPUParticles3D::restart() {
|
void GPUParticles3D::restart() {
|
||||||
RenderingServer::get_singleton()->particles_restart(particles);
|
RenderingServer::get_singleton()->particles_restart(particles);
|
||||||
RenderingServer::get_singleton()->particles_set_emitting(particles, true);
|
RenderingServer::get_singleton()->particles_set_emitting(particles, true);
|
||||||
|
|
||||||
|
emitting = true;
|
||||||
|
active = true;
|
||||||
|
signal_cancled = false;
|
||||||
|
time = 0;
|
||||||
|
emission_time = lifetime * (1 - explosiveness_ratio);
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AABB GPUParticles3D::capture_aabb() const {
|
AABB GPUParticles3D::capture_aabb() const {
|
||||||
@@ -425,9 +453,23 @@ void GPUParticles3D::_notification(int p_what) {
|
|||||||
// Use internal process when emitting and one_shot is on so that when
|
// Use internal process when emitting and one_shot is on so that when
|
||||||
// the shot ends the editor can properly update.
|
// the shot ends the editor can properly update.
|
||||||
case NOTIFICATION_INTERNAL_PROCESS: {
|
case NOTIFICATION_INTERNAL_PROCESS: {
|
||||||
if (one_shot && !is_emitting()) {
|
if (one_shot) {
|
||||||
notify_property_list_changed();
|
time += get_process_delta_time();
|
||||||
set_process_internal(false);
|
if (time > emission_time) {
|
||||||
|
emitting = false;
|
||||||
|
if (!active) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (time > active_time) {
|
||||||
|
if (active && !signal_cancled) {
|
||||||
|
emit_signal(SceneStringNames::get_singleton()->finished);
|
||||||
|
}
|
||||||
|
active = false;
|
||||||
|
if (!emitting) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -571,6 +613,8 @@ void GPUParticles3D::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align);
|
ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align);
|
||||||
ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align);
|
ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align);
|
||||||
|
|
||||||
|
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_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
|
ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ public:
|
|||||||
private:
|
private:
|
||||||
RID particles;
|
RID particles;
|
||||||
|
|
||||||
bool one_shot;
|
bool emitting = false;
|
||||||
|
bool active = false;
|
||||||
|
bool signal_cancled = false;
|
||||||
|
bool one_shot = false;
|
||||||
int amount = 0;
|
int amount = 0;
|
||||||
double lifetime = 0.0;
|
double lifetime = 0.0;
|
||||||
double pre_process_time = 0.0;
|
double pre_process_time = 0.0;
|
||||||
@@ -87,6 +90,10 @@ private:
|
|||||||
Vector<Ref<Mesh>> draw_passes;
|
Vector<Ref<Mesh>> draw_passes;
|
||||||
Ref<Skin> skin;
|
Ref<Skin> skin;
|
||||||
|
|
||||||
|
double time = 0.0;
|
||||||
|
double emission_time = 0.0;
|
||||||
|
double active_time = 0.0;
|
||||||
|
|
||||||
void _attach_sub_emitter();
|
void _attach_sub_emitter();
|
||||||
|
|
||||||
void _skinning_changed();
|
void _skinning_changed();
|
||||||
|
|||||||
Reference in New Issue
Block a user