godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.71k stars 20.83k forks source link

GPUparticle rigidbody collision snap delay #93073

Open ErrorFoundHere opened 3 months ago

ErrorFoundHere commented 3 months ago

Tested versions

-Reproducible in 4.2.1 and 4.3 and possibly earlier versions

System information

Godot v4.2.1.stable - Windows 10.0.22631 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3050 Laptop GPU (NVIDIA; 31.0.15.4633) - 11th Gen Intel(R) Core(TM) i5-11300H @ 3.10GHz (8 Threads)

Issue description

GPUparticle node seems to have what looks like an incorrect order of code execution when it comes to simulating collision.

The undesired behavior and potential cause The particles upon reaching their heightmap collision instead of snapping instantly to that collision position penetrate through the surface as if nothing was there for one more frame before finally snapping onto collision. The issue is more visible at greater velocities further, but the delay is always one frame, indicating that the GPUparticles likely move the particle after checking for collision, which produces a result of a particle moving into it's next position and rendering before it checks if it can move into that next position, only to check that it shouldn't have moved into that position in the next frame.

Importance of the issue This issue is extremely important for anyone who wants to use GPUparticle's collisions as this can produce some really undesirable results ranging from singular frames where the particles disappear (due to moving below the surface they hit) to making a proper rain collision impossible without needing to convert the particle material into a shader and having to compensate for the offset in code, not to mention how the issue is downright unfixable if you're using varied velocity.

Solution? Fixing the code that processes physics for GPUparticles, seeing as it is an issue with the engine's core functionality.

https://github.com/godotengine/godot/assets/100485785/4eac7740-bb99-41e6-b853-7b1a190f85df

Steps to reproduce

  1. Create a MeshInstance, give it a mesh (preferably something flat to better see the issue, it's present with any shape)
  2. Add a GPUParticles3D node
  3. In GPUParticles3D :
    • add a Draw Pass mesh of any kind (preferably a sphere)
    • assign a ParticleProcessMaterial to GPUParticles3D and set Collision -> Mode to Rigid
    • move the whole GPUParticles3D node a little bit up (to have some space between the Meshinstance below and the emitter)
  4. Add a GPUPariclesCollisionHeightField3D and change it's size property to 12m in every axis (at this point you can already notice the problem)
  5. Go to GPUParticles -> Process Material -> Spawn -> Velocity, change the Direction from (1,0,0) to (0,-1,0) and set Spread to 0
  6. Then test these values :

Initial_Velocity_Min = 30 Initial_Velocity_Max = 30

Initial_Velocity_Min = 90 Initial_Velocity_Max = 90

Initial_Velocity_Min = 12 Initial_Velocity_Max = 12

Initial_Velocity_Min = 24 Initial_Velocity_Max = 24

Once you've tested each setting you will notice that the scale of the issue directly correlates to velocity.

Minimal reproduction project (MRP)

The issue is too basic and fundamental for an MRP to be needed

Calinou commented 3 months ago

You can likely mitigate the issue by increasing Fixed FPS in the GPUParticles3D node (and possibly disabling Interpolate as well).

ErrorFoundHere commented 3 months ago

You can likely mitigate the issue by increasing Fixed FPS in the GPUParticles3D node (and possibly disabling Interpolate as well).

Wouldn't that come at a visible and unnecessary performance cost? It seems like a simple overlooked code construction flaw that should be easily fixable without needing to sacrifice performance like this, assuming that Fixed FPS is indeed about how many frames are processed in a second. Sounds expensive, and as you said -it would mitigate the issue, not eliminate it.