Surface collisions

Two ropes with surface collisions disabled. Only particles are considered for collision detection, so ropes pass cleanly trough gaps in between particles.
Same two ropes, with surface collisions enabled.

Since 6.0, Obi includes an advanced collision detection pipeline that will noticeably improve collision detection accuracy. You can use surface collisions with cloth, ropes and rods. Surface collisions for softbodies will likely be added in the future. Fluids are not compatible with surface collisions.

You can activate surface collisions in your actor's inspector:

For the most part, you can just enable them and be done with it. However there's some things to keep in mind when choosing surface collisions over regular, particle-based collisions. Also, contacts will contain slightly different information for actors using surface collisions, this is worth noting if you're using contact callbacks.

When to use them

  • Ropes/rods which heavily rely on self- or inter-collisions.
  • Actors that must accurately collide against sharp and/or small colliders (eg. box corners, thin cylinders, small spheres)
  • Situations in which no contact gap between the actor and colliders is acceptable.

When not to use them

  • Dense self-colliding cloth, as it will generate a lot of complex contacts. This will negatively affect performance.
  • Most character cloth, as particle-based collisions are often good enough.

Tips

If you are using surface collisions for an actor, chances are you can the reduce the amount of particles used in it. This will improve convergence speed and performance (since there's less particles and constraints to work with). For instance, reducing rope resolution and enabling surface collisions will result in a rope that's both faster and more robust. The same concept applies to cloth: thanks to surface collisions, lower resolution cloth can be used while maintaining high collision detection accuracy.

This low-resolution rope is a good candidate for surface collisions.
For a high-resolution rope, you can either disable surface collisions (particles already give good surface coverage) or decrease resolution and enable surface collisions.

Particles that are close to self-intersecting at rest will force the pipeline to perform a lot of self-intersection tests. This will negatively affect performance. It's better to use smaller particles, this will both improve performance and reduce contact gaps between the cloth and collider surfaces. Obi's continuous collision detection will take care of tunneling when using small particles.

Small particles ensure simplices don't intersect at rest, improving performance. This also reduces contact gaps.
Large particles cause lots of simplex self-intersections. This will negatively affect performance.

How it works

Surface collisions work by generating contacts between simplices, instead of individual particles. A simplex could be intuitively defined as the simplest possible convex shape in a given n-dimensional space.

  • In 0-dimensional space, a simplex is a point.
  • In 1-dimensional space, a simplex is a line.
  • In 2-dimensional space, a simplex is a triangle.
  • In 3-dimensional space, a simplex is a tetrahedron.

From left to right: a point, a line, a triangle and a tetrahedron.

By generalizing particles (points) to higher-order simplices, gaps in between particles disappear and the actor becomes a continuous surface. This allows for robust collision detection even with very few particles per actor. Ropes/rods use edges (aka lines, aka 1-dimensional simplices) to fuse particles into a smooth, continuous cylindrical surface. Cloth uses triangles (aka 2-dimensional simplices) to fuse particles into a smooth, flat continuous surface.

When surface collisions are disabled, all particles are considered points (aka 0-dimensional simplices). So, the traditional particle-based collision pipeline is just a particular case of surface collisions where all simplices are 0-dimensional.

Left: particle-based rope. Right: surface-based rope.
Left: particle-based cloth. Right: surface-based cloth.

Simplices are defined and stored in blueprints as particle index tuples. For instance, the simplex <1,3,4> is a triangle using particles 1, 3, and 4 as vertices. Simplex <7,8> is a line using particles 7 and 8 as vertices. Particle properties such as radius, mass, or velocity are interpolated over the surface of the simplex using barycentric interpolation, just like varying variables (eg. per-vertex colors) are interpolated to fragments in a rendering pipeline.

Let's take a look at how the 3 collision pipeline phases are altered when dealing with simplices instead of particles:

Broadphase

The broadphase works exactly like it does for particle collisions: all simplices are inserted into a spatial acceleration structure, then collision pairs are generated by testing for bounding box intersections and potential collision courses. It just deals with simplices instead.

Narrowphase

Once a potentially colliding pair (simplex-simplex or simplex-collider) has been detected, instead of performing a point-point or point-collider distance test Obi uses an iterative convex optimization algorithm (the Frank-Wolfe algorithm) to determine the actual contact point. This algorithm starts by guessing the contact point to be at the simplex barycenter, and progressively refines this guess over multiple iterations until a error tolerance threshold is reached. You can control the amount of iterations used as well as the tolerance threshold in the solver.

Iterative optimization of the contact point (green dot) between a 1-dimensional simplex (black line) and a triangle. The simplex is parallel to the triangle's normal. The gray dot at the center of the triangle is the initial guess.

There's three good reasons to use iterative optimization instead of closed-form intersection tests:

  • By adjusting the amount of iterations spent, you can trade precision for speed.
  • For complex pairwise tests (eg. triangle vs box) a few optimization iterations are often cheaper than the analytic solution.
  • It's simple, elegant and general: works for any n-dimensional simplex and any collider, convex or concave. All it needs is a distance function for colliders. This distance function can be either analytic or precalculated and stored into a distance field.
  • Collision projection

    To resolve a collision, the position of the simplices involved in the contact needs to be adjusted. This is done by calculating a position delta for the contact point, and interpolating it back to the particles using barycentric coordinates.

    A positional correction (black arrow) is calculated to take the contact point (black dot) outside the rectangular collider. This correction is distributed to each particle (orange arrows) using the contact point's barycentric coordinates.

    Shortcomings

    Simplices sharing at least one particle will not collide with each other, to avoid constraint fighting. For ropes this is not a problem at all. For cloth however, it can cause vertices to miss collisions against adjacent triangles. This is generally not an issue as it only takes place at the edges of crumpled cloth with close to zero bending resistance, where unsolved self-intersections are not apparent to the naked eye.

    Only one contact will be generated for each simplex-collider pair, at the closest points between both. This is no problem for most convex colliders (since two convex shapes can only have one contact manifold) but for concave colliders it can cause missing collisions in some situations, specially where "pointy" collider features are smaller than a single simplex. This is often not an issue as any unsolved collisions are generally detected and resolved in subsequent frames, but can result in jittering.

    Despite the line having 3 intersections with the gray collider, only one contact between them is generated.

    A box colliding with a single simplex results in jittering, since only one contact per frame is considered between them.
    A few more simplices ensure the box never needs more than one contact against the same simplex.