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

Fix GPUParticles3D emitting finished signal on ready #101596

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

TCROC
Copy link
Contributor

@TCROC TCROC commented Jan 15, 2025

Fixes a bug introduced by PR: #92089

The bug being that all gpu_particle_3ds emit the finished signal on ready.

Discussion in rocket chat can be found here: https://chat.godotengine.org/channel/vfx-tech-art/thread/WhhDnzLmTke5vYHF9

Details are as follows.

@QbieShay 's pr changes this method:

void GPUParticles3D::set_one_shot(bool p_one_shot) {
	one_shot = p_one_shot;
	RS::get_singleton()->particles_set_one_shot(particles, one_shot);

	if (is_emitting()) {
		if (!one_shot) {
			RenderingServer::get_singleton()->particles_restart(particles);
		}
	}
}

To

void GPUParticles3D::set_one_shot(bool p_one_shot) {
	one_shot = p_one_shot;
	RS::get_singleton()->particles_set_one_shot(particles, one_shot);

	if (is_emitting()) {
		if (!one_shot) {
			restart();
		}
	}
}

Specifically the part RenderingServer::get_singleton()->particles_restart(particles); being changed to restart(); is what introduces this bug. If we inspect the restart method, we see that some fields get set:

void GPUParticles3D::restart(bool p_keep_seed) {
	if (!p_keep_seed && !use_fixed_seed) {
		set_seed(Math::rand());
	}
	RenderingServer::get_singleton()->particles_restart(particles);
	RenderingServer::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);
	set_process_internal(true);
}

These fields are then evaluated in void GPUParticles3D::_notification here:

if (time > active_time) {
	if (active && !signal_canceled) {
		emit_signal(SceneStringName(finished));
	}
	active = false;
	if (!emitting) {
		set_process_internal(false);
	}
}

But you still may be wondering, who calls the set_one_shot method? That gets called by the constructor as can be seen by my debugger:

image

In summary, the issue is:

constructor calls set_one_shot -> calls restart -> sets fields incorrectly indicating particle system started -> GPUParticles3D::_notification sees that the particle system isn't running but incorrectly thinks it was started so it incorrectly emits the finished signal.

By reverting void GPUParticles3D::set_one_shot it goes back to behaving how it was before. To be thorough, I checked GPUParticles2D and can confirm this is how it is currently implemented over there so there is no bug with GPUParticle2D.

Thank you for the help debugging this @QbieShay! ❤️

@TCROC TCROC requested a review from a team as a code owner January 15, 2025 17:31
@TCROC
Copy link
Contributor Author

TCROC commented Jan 15, 2025

I discovered the issue because I have a script that emits all child particles when the parent particle emits his finished signal. As a result, all child particles emit on scene load.

@tool
extends Node3D
class_name GPUParticleSubeEmitterGroup3D

func _ready() -> void:
    (get_parent() as GPUParticles3D).finished.connect(on_parent_finished);

func on_parent_finished() -> void:
    for child in get_children():
        child.restart()
        if child is GPUParticles3D:
            child.emitting = true

@QbieShay realized the appropriate fix and I dug in to find the details as to why :)

@akien-mga akien-mga changed the title Fix gpu_particles_3d emitting finished signal on ready Fix GPUParticles3D emitting finished signal on ready Jan 15, 2025
@akien-mga akien-mga changed the title Fix GPUParticles3D emitting finished signal on ready Fix GPUParticles3D emitting finished signal on ready Jan 15, 2025
@clayjohn clayjohn self-requested a review January 15, 2025 21:08
Copy link
Member

@clayjohn clayjohn left a comment

Choose a reason for hiding this comment

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

This is going to need to update the seed still otherwise the one shot particle will look the exact same every time which is a change in behaviour

@TCROC
Copy link
Contributor Author

TCROC commented Jan 15, 2025

This is going to need to update the seed still otherwise the one shot particle will look the exact same every time which is a change in behaviour

Makes sense. I'll go update it to update the seed

@TCROC TCROC force-pushed the fix-gpu-particles-3d-emitting-finished-signal-on-ready branch from 7af2536 to d702e02 Compare January 15, 2025 21:38
@TCROC
Copy link
Contributor Author

TCROC commented Jan 15, 2025

@clayjohn It has been done 😎

@QbieShay
Copy link
Contributor

@clayjohn i'm not sure it's necessaary, this happens in the setter of oneshot and not on reset

@TCROC
Copy link
Contributor Author

TCROC commented Jan 15, 2025

Whatever the Godot powers that be command of me, I shall do 😎

@TCROC
Copy link
Contributor Author

TCROC commented Jan 15, 2025

I do agree with @QbieShay though. I personally don't care that much about it one way or the other. Yes doing this introduces (imo) an unnecessary call to randomize the seed since this is just a setter. But I don't call set_one_shot often (never actually in my case) to care one way or the other. So I didn't bother bringing it up as I'd rather the PR just go through. But if I am to offer some input, I do agree with @QbieShay that randomizing the seed should be left to the restart method rather than this setter. In most cases, doing it here will be redundant.

@TCROC
Copy link
Contributor Author

TCROC commented Jan 16, 2025

So I guess with that said, @clayjohn do you like it as it is (your suggestion) or would you like me to go back to the way the pr was (@QbieShay and my suggestion).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants