Thanks @Randy Gaul!
I had a look at the link. In case someone searches for this in the future, here is a condensed 3D version of the strategy used in the Box2D source link that Randy posted.
float GetSimplexMetric(const Simplex &s) {
const Vector3 sp = s.supportPoints;
switch (s.count) {
case 2: return (sp[1] - sp[0]).Norm();
case 3: return (sp[1] - sp[0]).Cross(sp[2] - sp[0]).Norm();
case 4: return (sp[1] - sp[0]).Cross(sp[2] - sp[0]).Cross(sp[3] - sp[0]).Norm();
}
return 0.0f;
}
void DoGJK(Cache* cache) {
Simplex s(cache->indices, /* New support points calculated from cached vertex indices */);
float metric = GetSimplexMetric(s);
if (newMetric < cache->metric * 0.5f || newMetric > cache->metric * 2.0f)) {
s.clear();
}
// Do normal GJK...
// Update the cache with the new simplex indices and the simplex metric
cache->set(s.indices, s.count);
cache->metric = GetSimplexMetric(s);
}
The idea is to build a metric that is proportional to the length/area/volume of the simplex and then throw away the simplex if this area changes by two big of a factor between frames.
The exact ratio of the limits are not so important from what I can tell. It seems to be more of a "better safe than sorry" kind of thing. The big win is in avoiding recalculation of the simplex for resting and near resting contacts.
Box2D uses factors 0.5 and 2.0 with a linear metric. So to get the same factors for a square metric like in the example above I guess you would use 0.25 and 4.0 instead. But I doubt there would be much difference in practice...