Click or drag to resize
DigitalRuneSmooth Movement over Triangle Mesh

This topic discusses a common problem that occurs when rigid bodies move over a static triangle mesh and factors which influence the triangle mesh interactions.

Problem

In my game I am rolling a small ball down a large, curved ramp which is a triangle mesh imported from a FBX file. Consider a ball rolling down a half-pipe. The problem is that although the ramp has a lot of faces on the curve, the ball will often bounce off the surface unnaturally.

Solution

Unnatural bounces at triangle edges can have several causes and here are a few things you can try:

Contact welding

Bounces can be caused by bad normal vectors at triangle edges. Enable contact welding for the mesh:

C#
triangleShapeMesh.EnableContactWelding = true;

and make the welding more aggressive by setting the welding limit to 1. This is a static property of the TriangleMeshAlgorithm class:

C#
TriangleMeshAlgorithm.WeldingLimit = 1f;

Contact welding improves the contact normal vectors at triangle edges.

Perfect sphere contacts

Normally, when a sphere touches another object, the contact normal vector points in the direction from the sphere center to the contact. When contact welding is used, the contact positions can be a bit off. - But small errors can cause visible bounces. We can correct this with a custom contact filter:

C#
public class MyContactFilter : IContactFilter 
{ 
  private ContactReducer _defaultContactFilter = new ContactReducer(); 
  
  public void Filter(ContactSet contactSet) 
  { 
    // Call the default contact filter. 
    _defaultContactFilter.Filter(contactSet); 
  
    // Abort if there are no contacts in this contact set. 
    if (contactSet.Count == 0) 
      return; 
  
    // If this is a sphere vs. * contact set, then we correct the position of the  
    // contact point to make sure that the contact position is in line with the sphere center. 
  
    var sphere = contactSet.ObjectA.GeometricObject.Shape as SphereShape; 
    if (sphere != null) 
    { 
      float radius = sphere.Radius; 
  
      foreach(var contact in contactSet) 
        contact.Position = contactSet.ObjectA.GeometricObject.Pose.Position + contact.Normal * (radius - contact.PenetrationDepth / 2); 
           
      return; 
    } 
  
    sphere = contactSet.ObjectB.GeometricObject.Shape as SphereShape; 
    if (sphere != null) 
    { 
      float radius = sphere.Radius; 
      foreach (var contact in contactSet) 
        contact.Position = contactSet.ObjectB.GeometricObject.Pose.Position - contact.Normal * (radius - contact.PenetrationDepth / 2); 
    } 
  } 
}

Set this filter with:

C#
simulation.CollisionDomain.CollisionDetection.ContactFilter = new MyContactFilter();

Usually, when you use contact welding and this contact filter, you get a very smooth movement. If this does not help, here are a few more things you can try:

Lower friction

Try to use a lower friction. If the friction is lower, the spheres can glide more smoothly over bumps.

Allowed penetration depth

Try to lower the allowed penetration depth. For example:

C#
simulation.Settings.Constraints.AllowedPenetration = 0.001f;

If this parameter is high (which is not good in your case), then the sphere will sink more into the triangle surface. And when it rolls to a triangle edge, it will perceive the neighbor edge as a small upwards step.

Gravity

When the gravity is high, small bumps can have a higher impact. Try to use a lower gravity, for example:

C#
simulation.ForceEffects.Add(new Gravity() { Acceleration = new Vector3F(0, -5, 0)});

Height field instead of triangle mesh

Try to use a height field instead of a triangle mesh - if your scenario allows to use a height field.

Distorted triangles

If your triangles are very distorted (one side is small relative to the other sides), subdivide your mesh to create more regular triangles. Very long, distorted shapes will create high numerical errors in many collision detection and physics algorithms.