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

After enabling BVH in 2d physics, set monitorable to true for more than 4000 area through the Physic2DServer will cause an instantaneous permanent huge drop in performance #54171

Open
Xwdit opened this issue Oct 23, 2021 · 7 comments

Comments

@Xwdit
Copy link
Contributor

Xwdit commented Oct 23, 2021

Godot version

3.4.rc(62f56af)

System information

Windows 11, RTX 2060, GLES2/GLES3

Issue description

After enabling BVH in 2d physics, set monitorable to true for more than 4000 area through the Physic2DServer will cause an instantaneous and permanent huge drop in performance.

Steps to reproduce

Enable Bvh in 2D physics settings, and then use Physic2DServer to create some areas (more than 4000). Then gradually set monitorable to true for these areas. When the number of active areas reaches 4000 or more, the original 144fps will instantly drop below 15fps, and will drop below 5fps within 3 seconds.

After disabling BVH, the FPS does not start to decrease from 144 until there are 7000 active areas, and until 12000 active areas the FPS are still able to remain above 60.

Minimal reproduction project

I am using a C++ custom module to control the behavior of the area through Physics2DServer, so it may not be possible to provide a minimal project.

But I can guarantee that there is nothing in my module that will affect the physical behavior of Godot, because it simply calls Physic2DServer-related functions. And after many comparative tests, it is confirmed that this problem is caused by BVH

2021-10-24.01-50-27.mp4

(In the video, due to screen recording, the base fps dropped to 90-100, but this problem is still very obvious)

@Xwdit Xwdit changed the title After enabling BVH in 2d physics, creating more than 4000 area through the Physic2DServer will cause an instantaneous huge drop in performance After enabling BVH in 2d physics, set monitorable to true for more than 4000 area through the Physic2DServer will cause an instantaneous huge drop in performance Oct 23, 2021
@Xwdit Xwdit changed the title After enabling BVH in 2d physics, set monitorable to true for more than 4000 area through the Physic2DServer will cause an instantaneous huge drop in performance After enabling BVH in 2d physics, set monitorable to true for more than 4000 area through the Physic2DServer will cause an instantaneous permanent huge drop in performance Oct 23, 2021
@akien-mga akien-mga added this to the 3.4 milestone Oct 24, 2021
@lawnjelly
Copy link
Member

This will require a minimum reproduction project.
Another thing to try is try with the previous 3.4 beta, just in case it is a regression from #54108. It probably isn't but it would be good to remove that as a possibility.

@samdze
Copy link
Contributor

samdze commented Oct 27, 2021

I experienced the same thing making my plugin Native Bullets.
Instead of creating lots of areas I create lots of area shapes, but the performance drop is pretty much the same.
There's also a step by step tutorial in the README, it could be useful to test the issue.

@lawnjelly
Copy link
Member

lawnjelly commented Oct 27, 2021

Ah unfortunately I can't see a Bullets node when I try your addon (Linux Mint 20, 64 bit). Maybe it's a runtime library versioning issue (e.g. GLIBC etc). Ideally a minimum reproduction project would be in gdscript (even if the effect is less pronounced).

This may well just be a result of different collision margins in BVH and the old implementation (BVH will by default report more collisions). The parameters are configurable but they aren't exposed to the user, I think @pouleyKetchoupp did some tests on the 2D parameter settings. But we'll know more once we can replicate.

@samdze
Copy link
Contributor

samdze commented Oct 27, 2021

Bullets is set as an autoload in the examples, should work once you set it.
Today I'll also try with the new 3.4 RC2 to see if it changes anything.

EDIT: alright, nothing seems to change. With 7000 objects I get pretty consistent 400+ fps with hash grid, but only around 120 with bvh with huge occasional drops to around 30 fps.

@lawnjelly
Copy link
Member

It's very probably the collision margin. We may have to think about whether to expose it to the user. It's pretty much this:

Say you have 1000 objects moving, in theory you need to collision test each object 999 times after each move. This is very expensive.

If those 1000 objects aren't moving, you don't need to collide test them, super cheap.

If they are only moving a tiny amount it seems unlikely they would collide, so it seems silly to do full check. So instead we add a collision margin around each object. When it first adds, the collision testing is done with the expanded bound. Then when it moves, providing the new AABB doesn't move outside the expanded bound, there is no need to do a collision check. When it does move outside, you create a new expanded bound, do a full collision check etc.

This means you can usually cut down the number of moving objects by quite a large amount on any particular tick / movement, which saves a shedload of processing.

The flipside is, as the collision margins are larger, any two close objects are going to be registered as in collision at a further distance. This isn't a problem in many cases, and especially in physics, this broadphase check should be followed by a narrowphase check, which takes into account the shape of the object, not just the AABB. For instance two rods may not be in collision even though their AABBs overlap.

What seems to be happening is that there is no narrowphase going on here, and the broadphase collision is being reported as a collision.

There's a few ways of addressing this:

  1. Add a proper narrowphase (taking into account shape) and use this to determine whether to call monitor callbacks
  2. Add a secondary more accurate intermediate AABB check at the end of the BVH and use this for user callbacks
  3. Reduce the collision margin / make it user definable

So you can see that the collision margin is a trade off. In most cases having a margin will be beneficial, but in particular special cases (e.g. bullet hell with collision) it could have negative effects. I did initially expose this in the first PR (for 3d rendering) but removed the project settings to avoid confusion, and because they didn't seem hugely important to reduce for rendering.

Another option which I did try but ran out of time to finish is like an auto-adjusting system that varies the collision margin on the fly. This also can help because to some extent the best collision margin depends on the world size and the average speed of movement of objects.

Anyway that is very likely what you are seeing - the other systems (physics / monitoring) are unable to cope with large numbers of collisions.

@pouleyKetchoupp
Copy link
Contributor

pouleyKetchoupp commented Oct 28, 2021

I haven't run any tests yet, but just to add two things to @lawnjelly's insightful explanation:

  • I want to try and add a precise AABB check on the physics server side before doing the expensive narrowphase process. It might help alleviate the issue (but probably won't solve it entirely).
    Option 2 (precise AABB check in the BVH) also seems like it could help a lot without making the system too complicated.

  • I'm planning to backport Godot Physics collisions and solver processed on threads #48221 as a project option for 3.5. It would allow collision checks to run in parallel in the physics server, which can improve performance drastically whether BVH is enabled or not.

@akien-mga akien-mga modified the milestones: 3.4, 3.5 Nov 8, 2021
@gokiburikin
Copy link

I was about to open an issue on this, but after a search I believe this is also the issue I'm experiencing. In my case I am doing it all through the Physics2DServer while the BVH Collision Margin is 1. This results in significantly worse performance than using the Hash Grid.

I worked around this in my project: since all the testing in my game is done by the bullet testing their motion against enemies and enemies never actually collide, using a high collision margin (which I assumed would reduce collision accuracy) seems to have no effect so I can use that to gain back lost performance.

Attached is a video of the performance and the associated MRP for v3.5.beta5.official [815f7fe]. To test with, apply some of these changes:

  • Toggle physics/2d/use_bvh
  • Change physics/2d/bvh_collision_margin 1 and then 20 (0 is the worst case)
  • Toggle Update Shape Transform Check Box
x264.2022-05-30_11-22-33.mp4

bvh-regression-mrp.zip

@lawnjelly lawnjelly modified the milestones: 3.5, 3.x Mar 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants