Skip to content

Conversation

@etodd
Copy link
Contributor

@etodd etodd commented Aug 21, 2024

Fixes #85213, fixes #50824, fixes #65390.

Attached is a test project which pauses and unpauses every second, and includes:

  • A GPUParticles2D with gravity, tangential acceleration, and turbulence.
  • A GPUParticles3D with gravity, tangential acceleration, and turbulence.
  • A GPUParticles3D with gravity and particle trails.

This PR is based on #89991, but in my testing, that PR changed the behavior of turbulence when the fixed FPS is set to anything other than 30.

particle-pause-jitter-fix.zip

@etodd etodd requested a review from a team as a code owner August 21, 2024 17:54
@AThousandShips AThousandShips added bug regression topic:particles cherrypick:4.3 Considered for cherry-picking into a future 4.3.x release cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release labels Aug 21, 2024
@AThousandShips AThousandShips added this to the 4.4 milestone Aug 21, 2024
@clayjohn
Copy link
Member

I tested and can confirm that this fixing the issue with pausing, but this does not fix #50824 as that issue includes low speed scale. Using a low speed scale in the MRP still reliably reproduces the issue.

I suspect that much of this issue comes from the particles interpolation which happens in the copy shader. The frame_remainder is passed in here:

copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;

And used here:

txform[3].xyz += particles.data[particle].velocity * params.frame_remainder;

You should check the values of frame remainder, as it must be fluctuating when it shouldn't. I agree that #89991 probably isn't the right approach. But its interesting to see that suppressing velocity was enough. That indicates to me that the core of the issue is in the interpolation (which is just frame-remainder * velocity)

Also note, that the same fixes will need to be implemented for the compatibility renderer too: https://github.com/godotengine/godot/blob/master/drivers/gles3/storage/particles_storage.cpp

@etodd
Copy link
Contributor Author

etodd commented Aug 22, 2024

Thanks for the review. 🙏 You're right, frame_remainder is the issue. I think it's supposed to advance according to the engine time scale * the particle time scale.

I simplified the logic a bit when fixed_fps > 0 and the time scale is zero. The old logic called _particles_process(particles, 0.0) every frame. Now it stops calling it (unless particles->clear is true). I think this is right?

@etodd
Copy link
Contributor Author

etodd commented Aug 26, 2024

I ran the attached test scene with the following settings:

  • Forward plus renderer
  • Forward plus renderer with Engine.time_scale = 0.5
  • Compatibility renderer
  • Compatibility renderer with Engine.time_scale = 0.5

Any other scenarios I should test this with?

@Mickeon Mickeon requested a review from clayjohn August 29, 2024 15:47
@QbieShay QbieShay self-assigned this Aug 29, 2024
@clayjohn
Copy link
Member

clayjohn commented Sep 3, 2024

Yes, you should test with a low speed_scale like in #50824

@etodd etodd force-pushed the particle-pause-jitter-fix branch from c4a9161 to 97b2c01 Compare September 3, 2024 03:26
@etodd
Copy link
Contributor Author

etodd commented Sep 3, 2024

Thanks for the suggestion! I did some more testing with low engine time scale and low particle system speed scale. Turns out I had the engine time scale multiplied in there when it wasn't needed, and I also needed to remove the particle system speed scaling from inside _particles_process, since it's now applied outside it.

The only other scenario where _particles_process is called is during pre-processing. I believe the way it is in this PR is correct - the particle system speed scale is not applied here. If the particle lifetime is 1 second and I set the pre-process time to 1 second, I expect it to pre-process 1 complete particle lifetime, regardless of the speed scale.

I also went ahead and rebased the PR on top of the master branch.

@QbieShay
Copy link
Contributor

QbieShay commented Sep 3, 2024

Please double check its current behaviour. If currently preprocess takes speed_scale into account, it should continue to do so.

@etodd
Copy link
Contributor Author

etodd commented Sep 3, 2024

Currently preprocess does take speed_scale into account, but I believe this is a bug. For example, if you spawn a particle system with preprocessing enabled while the SceneTree is paused, it will do the preprocessing, but it won't have any effect because the speed scale is 0.

Here's a sample project demonstrating that. It pauses the SceneTree, waits two seconds, then spawns a particle system with some preprocessing (which will not actually occur on master branch, you won't see anything). With this PR, you should see the particle system spawn with correct preprocessing.

particle-pause-jitter-fix.zip

That said, I understand if it's desirable to maintain the current behavior for other reasons. Happy to defer if that's the decision.

@etodd
Copy link
Contributor Author

etodd commented Sep 10, 2024

Any other thoughts on this? One slightly annoying thing is that at low speed scales, the interpolation becomes very obvious. It would be great if the fixed FPS automatically adjusted with the time scale so it actually simulates at the desired FPS regardless of speed scale. But maybe that would be best addressed in a separate PR.

@Calinou
Copy link
Member

Calinou commented Sep 16, 2024

It would be great if the fixed FPS automatically adjusted with the time scale so it actually simulates at the desired FPS regardless of speed scale. But maybe that would be best addressed in a separate PR.

Changing fixed FPS can affect particle behavior in an undesired manner, especially when collision is involved. Also, changing fixed FPS at runtime can introduce visible jitter, and the FPS must be an integer value (while the time scale is a float). Therefore, automatic adjustment based on time scale should be an opt-in property discussed in a separate proposal.

Note that the particle interpolation is currently more obvious than it could be due to some properties not being interpolated: #51318
Once this is done, it'll look a lot better.

@QbieShay
Copy link
Contributor

@etodd I am working on a PR to request particle process that will work even if the scene tree is paused. I think preprocess should stay as it is right now, and we'll be able to tackle the usecase you mentioned once my PR is in!

@QbieShay
Copy link
Contributor

Seek PR: #92089

@etodd etodd force-pushed the particle-pause-jitter-fix branch from 25e17a2 to d19891f Compare January 19, 2025 05:12
@etodd
Copy link
Contributor Author

etodd commented Jan 19, 2025

@QbieShay I think your changes fixed the preprocessing bug. 🎉 Which means this PR should now have no effect other than fixing the jitter. I rebased the PR and it still works on my test projects.

@etodd
Copy link
Contributor Author

etodd commented Jan 19, 2025

Re-tested the first test project with Engine.time_scale at 1.0 and 0.1, and on forward+ and compatibility renderer.

Also checked the preprocess behavior on the second test project is the same on 4.4-beta1 and this branch.

@Repiteo Repiteo added the cherrypick:4.4 Considered for cherry-picking into a future 4.4.x release label Feb 24, 2025
@Repiteo Repiteo modified the milestones: 4.4, 4.5 Feb 24, 2025
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.

Discussed in the rendering meeting today. This looks fine to me

@etodd etodd force-pushed the particle-pause-jitter-fix branch from d19891f to 87efa4d Compare February 27, 2025 16:54
@etodd
Copy link
Contributor Author

etodd commented Feb 27, 2025

Rebased and re-tested!

@akien-mga akien-mga merged commit daa28e8 into godotengine:master Mar 4, 2025
20 checks passed
@akien-mga
Copy link
Member

Thanks!

@akien-mga akien-mga removed the cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release label Mar 12, 2025
@akien-mga
Copy link
Member

Cherry-picked for 4.4.1.

@akien-mga akien-mga removed the cherrypick:4.4 Considered for cherry-picking into a future 4.4.x release label Mar 12, 2025
@BaconEggsRL
Copy link

BaconEggsRL commented Mar 17, 2025

Nice! Just ran into this issue on 4.4 and tested with 4.4.1, and it's fixed
Love that :D

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

Labels

bug cherrypick:4.3 Considered for cherry-picking into a future 4.3.x release topic:particles

8 participants