appsinacup / godot-rapier-physics

Godot Rapier Physics – 2D and 3D physics engine for the Godot game engine. with better stability, performance, liquids, determinism, state serialization and no ghost collisions.
https://godot.rapier.rs
MIT License
394 stars 22 forks source link

Rapid performance degradation #248

Closed Hirmuolio closed 3 weeks ago

Hirmuolio commented 1 month ago

Describe the bug

At first everything seems to work fine but after few tens of seconds performance suddenly tanks.

See the profiler graph below.

performance

Performance is fine with default physics.

To Reproduce

EDIT: See the comment below instead. The trigger seems to be move_and_slide with rapid rotation.

Run world.tscn in the example project with rapier physics.

The scene has 72 CharacterBody2d which move around and use ray-casting (8 rays per physics frame per unit) to avoid colliding with walls and each other.

Profiler says this part is where all the time is spent.

func set_weight()->void:
    var space_state : PhysicsDirectSpaceState2D = get_world_2d().direct_space_state
    var current_direction : Vector2 = Vector2.from_angle( rotation )
    weights.fill(0)
    for i : int in num_rays:
        var query : PhysicsRayQueryParameters2D = PhysicsRayQueryParameters2D.create( position, position+ray_directions[i]*50, 1 )
        var result : Dictionary = space_state.intersect_ray( query )
        if result:
            weights[i] = - 100 / (position - result.position ).length_squared()
        weights[i] += max( current_direction.dot( ray_directions[i] ), 0 ) + 2

Expected behavior

Performance stays constant.

Environment:

Example project(zip)

test_project.zip

Ughuuu commented 1 month ago

Interesting, so the intersect_ray is slow then? But only after some time, which makes me think its either memory leak or during that time more objects are closer?

Havent had a chance yet to reproduce it locally, will add more info when i do.

As for this bug, does it also happen with less objects? Or only with 70-ish?

Ughuuu commented 1 month ago

Just to check, if you remove the intersect_ray all togheter, is performance better? Or is there another bottleneck to?

Edit: Thanks for reporting the bug!

Hirmuolio commented 1 month ago

After some more testing it appears it maybe wasn't the rays that caused the problem.

I changed te code so that the mobs just turn to random angle on every frame and then call move_and_slide() and that was enough to trigger it.

The mobs just didn't do any turning without the rays and perhaps the rays made it worse.

extends CharacterBody2D

var rng = RandomNumberGenerator.new()

func _physics_process( _delta: float) -> void:
    rotation = rng.randf_range(-PI, PI)
    move_and_slide()

More mobs makes it happen faster. With 144 units performance goes bad at ~8 seconds, with 72 it tok ~26 seconds. With 10 units I waited few minutes and saw nothing.

Here new example project.

test_project.zip

Ughuuu commented 3 weeks ago

Now that I added serialization it seems that the query_pipeline keeps on growing for every raycast done. I'll check the docs to see if i'm using rapier lib wrongly and not reseting some state or something.

Ughuuu commented 3 weeks ago

Looking at docs: https://rapier.rs/docs/user_guides/rust/scene_queries/ I am not calling query_pipeline.update. It's strange it even worked until now :|

Edit: No, I am calling indirectly incremental_update actually. Hm..

Ughuuu commented 3 weeks ago

This seems to be the issue: https://github.com/dimforge/rapier/issues/749 For now I think I will do full updates of query_pipeline every time until this is fixed to avoid it growing indefinitely.