Hi @n16, welcome!
Our warnings against any-hit programs are really only intended to make people aware of the costs of any-hit in cases where any-hit is not actually needed. This is mostly because any-hit programs are turned on by default and you have to opt-out. Sometimes, any-hit programs are needed, and in that case I don’t want people to feel bad about using the feature as it was intended.
There are three ways I can think of to collect multiple hits along a ray: (1) any-hit, (2) use side-effect code in an intersection program, and (3) iteratively query for the closest hit and then re-cast a new ray from the previous hit point.
OptiX currently will not return intersections for hardware triangles at t<=0, and the closest-hit order for co-incident geometry is undefined. This means the iterative closest-hit approach will not work for you because you won’t be able to catch both hits of two or more co-incident triangles. Unfortunately, this also means the any-hit won’t work either when the origin is co-incident with your co-incident triangles. If your triangles aren’t lying in an axial plane like z=0, then you might catch some of the hits sometimes due to floating point rounding discrepancies between the triangle plane and your ray origin, but that’s uncontrollable and I’m sure you don’t want your case to depend on floating point rounding.
So I guess the solution would be to use any-hit or a custom intersection. With any-hit you’d have to move the ray origin off the co-incident plane (perhaps scaled by the triangle’s normal or some other handy direction that doesn’t lie in the triangles’ plane) and then narrow your t-min and t-max values to a reasonable and safe window, and filter out any unwanted hits as part of your any-hit processing. Or, you can write a custom primitive intersection program, and then you will be able to handle t=0 if you want, without having to move the ray origin. Using a custom primitive intersection program will have a slightly higher cost than any-hit, since the intersection itself will be software.
This is an interesting use case, can you elaborate on what you’re doing with multiple intersections at the ray origin? The use case that seems to get questions more often is trying to do the opposite and avoid getting any ray hits at the ray origin. ;) (For example, when casting shadow rays away from a surface, you don’t want the surface to count as a hit, otherwise it will shadow itself.)