Invalid collision / contact from performCollisionDetection & getContactPoints after many createMultiBody / removeBody calls
manuel-koch opened this issue · comments
I'm using pybullet
to find collisions / contacts of huge scenes with many thousand bodies ( build from convex OBJ meshes ).
I'm not interested in dynamics, I just want to query the "static" scene as-is and find bodies
that are in collision in this static state of the scene.
A scene is build by
- adding initial static bodies
- loop
- adding additional static bodies
- performing collision detection
- removing the additional static bodies afterwards
In general this seems to work as expected, but sometimes false collisions / contacts are found between body A & B,
i.e. a collision of actually two distinct bodies A & B that are not even touching.
If I try to double check those false collisions by re-building the scene from scratch incl. bodies A & B
( i.e. only adding those bodies that were in the scene when the collision check was done ),
I can't find those false collisions anymore, i.e. I get the expected results.
My environment is
- MacOS Ventura 13.4, M1 arm
- Python 3.10.6
- pybullet==3.2.5
Pseudo code of my application:
physics_client = bullet.connect(bullet.DIRECT)
# add many "static" bodies
for i in my_static_bodies:
collision_shape_id = bullet.createCollisionShape(....)
bullet.createMultiBody(baseCollisionShapeIndex=collision_shape_id,....)
while keep_going:
# add intermediate "static" bodies
for i in my_additional_static_bodies:
collision_shape_id = bullet.createCollisionShape(....)
bullet.createMultiBody(baseCollisionShapeIndex=collision_shape_id,....)
bullet.performCollisionDetection(physics_client)
for contact in bullet.getContactPoints(physicsClientId=physics_client):
# Handle the colliding bodies doing business logic. Not modifying the bodies in any way.
#
# Sometimes false collisions are reported, i.e. reporting bodies in collision that are actually distinct, not even touching.
# Even the contact points are away from any of the two bodies that are supposedly in collision.
# remove intermediate "static" bodies
for i in my_additional_static_bodies:
bullet.removeBody(....)
Any help / idea appreciated - maybe I'm using pybullet
in a way that is wrong or not supported ?
Additionally I noticed that contacts are reported for bodies that have been removed.
I even see contacts for the same body getting reported.
Using a simple AABB overlap check shows that the supposedly colliding bodies are distinct.
from typing import Tuple
for contact in bullet.getContactPoints(physicsClientId=physics_client):
(
contact_flag,
body_unique_id_a,
body_unique_id_b,
link_index_a,
link_index_b,
position_on_a,
position_on_b,
contact_normal_on_b,
contact_distance,
normal_force,
lateral_friction_1,
lateral_friction_dir_1,
lateral_friction_2,
lateral_friction_dir_2,
) = contact
if body_unique_id_a == body_unique_id_b:
continue
# I keep a list of all body IDs that are in the scene
if (
body_unique_id_a not in used_body_ids
or body_unique_id_b not in used_body_ids
):
# bullet seems to return body IDs we have already removed
continue
aabb_a = bullet.getAABB(body_unique_id_a, physicsClientId=physics_client)
aabb_b = bullet.getAABB(body_unique_id_b, physicsClientId=physics_client)
if not aabb_overlap(aabb_a, aabb_b, tolerance=0.15):
continue
AABB = Tuple[Tuple[float, float, float], Tuple[float, float, float]]
def aabb_overlap(aabb1: AABB, aabb2: AABB, tolerance: float = 0):
"""
Returns true if aabb1 and aabb2 overlap using given tolerance.
"""
return (
aabb1[0][0] - tolerance <= aabb2[1][0] + tolerance
and aabb1[1][0] + tolerance >= aabb2[0][0] - tolerance
and aabb1[0][1] - tolerance <= aabb2[1][1] + tolerance
and aabb1[1][1] + tolerance >= aabb2[0][1] - tolerance
and aabb1[0][2] - tolerance <= aabb2[1][2] + tolerance
and aabb1[1][2] - tolerance >= aabb2[0][2] - tolerance
)