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

Implement collision margin #393

Merged
merged 6 commits into from
Jul 3, 2024
Merged

Implement collision margin #393

merged 6 commits into from
Jul 3, 2024

Conversation

Jondolf
Copy link
Owner

@Jondolf Jondolf commented Jul 2, 2024

Objective

Collisions for thin objects such as triangle meshes can sometimes have stability and performance issues, especially when dynamically colliding against other thin objects.

  • Infinitely thin objects are more prone to numerical issues and tunneling. Two trimeshes colliding against each other can easily get stuck in an intersecting state or have other collision issues.
  • Collision algorithms for intersecting objects are typically more expensive than for the non-intersecting state. Trimesh collisions can be very expensive if the trimesh has dense geometry.

To allow users to mitigate these issues when necessary, engines such as Rapier and Bullet provide a collision margin or contact skin that forces the solver to maintain an artificial separation distance between objects. It can be thought of as a kind of shell that adds thickness to colliders, reducing the issues mentioned above.

Solution

Add a CollisionMargin component. It can be used to add artifical thickness to any collider for collisions.

commands.spawn((
    RigidBody::Dynamic,
    Collider::trimesh_from_mesh(&mesh),
    CollisionMargin(0.05),
));

Without a collision margin:

2024-07-02.22-07-55.mp4

With a collision margin:

2024-07-02.22-09-28.mp4

@Jondolf Jondolf added C-Enhancement New feature or request A-Collision Relates to the broad phase, narrow phase, colliders, or other collision functionality A-Dynamics Relates to rigid body dynamics: motion, mass, constraint solving, joints, CCD, and so on labels Jul 2, 2024
src/collision/collider/mod.rs Show resolved Hide resolved
src/collision/collider/mod.rs Show resolved Hide resolved
src/collision/collider/mod.rs Outdated Show resolved Hide resolved
src/collision/narrow_phase.rs Outdated Show resolved Hide resolved
@@ -552,6 +608,7 @@ impl<'w, 's, C: AnyCollider> NarrowPhase<'w, 's, C> {
body2: &RigidBodyQueryReadOnlyItem,
collider1: &ColliderQueryItem<C>,
collider2: &ColliderQueryItem<C>,
collision_margin: Scalar,
Copy link
Sponsor Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
collision_margin: Scalar,
collision_margin: CollisionMargin,

It's weird to refer to CollisionMargin in the docs and then not actually use that type.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like having to wrap everything in newtypes unnecessarily so I changed this (and the other similar cases) to impl Into<CollisionMargin> and derived From<Scalar> for now. Not sure if it's worth it though, since the newtypes don't really give an API benefit (other than explicitness and docs) and it just means that we need to call .into() and use derefs in more places internally

src/collision/narrow_phase.rs Outdated Show resolved Hide resolved
@@ -91,6 +91,7 @@ impl ContactConstraint {
collider_entity2: Entity,
collider_transform1: Option<ColliderTransform>,
collider_transform2: Option<ColliderTransform>,
collision_margin: Scalar,
Copy link
Sponsor Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
collision_margin: Scalar,
collision_margin: CollisionMargin,

if we already have the newtypes, we should also be consistently using them imo

src/dynamics/ccd/mod.rs Show resolved Hide resolved
Comment on lines 454 to 462
let collision_margin1 = collider1.collision_margin.map_or(
rb_collision_margin1.map_or(0.0, |margin| margin.0),
|margin| margin.0,
);
let collision_margin2 = collider2.collision_margin.map_or(
rb_collision_margin2.map_or(0.0, |margin| margin.0),
|margin| margin.0,
);
let collision_margin_sum = collision_margin1 + collision_margin2;
Copy link
Sponsor Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is duplicated. Consider extracting it into a method.

@janhohenheim
Copy link
Sponsor Contributor

Math checks out, just some code quality issues, nothing big :)

@Jondolf Jondolf merged commit c2a2ab3 into avian Jul 3, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Collision Relates to the broad phase, narrow phase, colliders, or other collision functionality A-Dynamics Relates to rigid body dynamics: motion, mass, constraint solving, joints, CCD, and so on C-Enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants