PhysX ray-casting precision


I’ve been using PhysX for doing ray-casting onto triangle meshes. In my application I need to find all intersections of the ray with the triangle mesh (regardless of whether it’s inside/outside or how many hits there are).

I noticed that in some cases when the ray hits near the edge or vertex of a triangle, multiple hits are found in more or less the same location. I looked into the code and it seems PhysX uses the Möller–Trumbore intersection algorithm for calculating the intersection of a ray with a triangle.

In the comments it is mentioned that this method uses an epsilon which is influenced by the size of the triangle in question. So the larger the triangle, the less precise the method becomes. So what is happening is that the ray is finding intersections with multiple triangles where I would expect a single hit.

Is there any way to modify the epsilon somehow so that I only get a single hit in these cases? Making the epsilon a fixed value would also solve the issue. I could merge hits within a certain epsilon from each other but the way it is now, it is impossible to know which hits to merge as the epsilon could be any value.

I am using the PxGeometryQuery::raycast function at the moment but I saw you can also do a scene ray-cast which allows you to specify a PxQueryFilterCallback. Would I be able to solve my issue using the filter callback? If so, can I also use the filter callback in PxGeometryQuery::raycast somehow or do I have to use a scene raycast?

I’ve looked into this a bit more and it seems I made some wrong assumptions/misunderstood the code. The epsilon is not relative, but just not the value I was expecting.

When I look at the value of mGeomEpsilon it is 0.0128…, is there a way to influence the value of this epsilon? Is it defined via the tolerance scale set in the cooking parameters? If so, how does the tolerance translate into the epsilon?

there is a large comment about this geometric epsilon in the code:
// Derive a good geometric epsilon from local bounds. We must do this before bounds extrusion for heightfields.
// From Charles Bloom:
// “Epsilon must be big enough so that the consistency condition abs(D(Hit))
// <= Epsilon is satisfied for all queries. You want the smallest epsilon
// you can have that meets that constraint. Normal floats have a 24 bit
// mantissa. When you do any float addition, you may have round-off error
// that makes the result off by roughly 2^-24 * result. Our result is
// scaled by the position values. If our world is strictly required to be
// in a box of world size W (each coordinate in -W to W), then the maximum
// error is 2^-24 * W. Thus Epsilon must be at least >= 2^-24 * W. If
// you’re doing coordinate transforms, that may scale your error up by some
// amount, so you’ll need a bigger epsilon. In general something like
// 2^-22W is reasonable. If you allow scaled transforms, it needs to be
// something like 2^-22
// PT: TODO: runtime checkings for this
PxReal geomEpsilon = 0.0f;
for (PxU32 i = 0; i < 3; i++)
geomEpsilon = PxMax(geomEpsilon, PxMax(PxAbs(localBounds.maximum[i]), PxAbs(localBounds.minimum[i])));
geomEpsilon *= powf(2.0f, -22.0f);