Andrew Kensler and Thiago Ize have been helping me tune up my ray-box code trying to find a sweet-spot of fast and simple. I've updates a few test cases here and added the new method Andrew sent me. Andrew's new code a super-simple version that on some compilers/machines is very competitive with the Amy Williams method, and you don't have to muck up your ray class. It's not as fast under clang on my mac (but hard-coding swap helped a little) but it's so simple it will be my go-to method for the time being.
If there are NaN the compare will fail and it returns false. It handles the inf cases right. Very clean!
Maybe that's nit-picking, but I'd argue the "<=" in the exit condition should be replaced with a "<".
ReplyDeleteThe way the code is right now (well, at least the way I read it :-) ) is that it would _reject_ the box test if the ray interval is exactly zero (i.e., t0==t1), but if you do that then that box test would be problematic in a BVH if you have any "planar" triangles, since in that case some of the min() and max() coordinate will be the same, and t0 will end up being equal to t1.
Sorry I didn't notice this comment before. I am guessing you'd want that because you want to use a box as an actual geometric primitive and get the normal vector and all that? People haven't written much about it but Morgan McGuire has been looking at it lately. You can get the point by just using ray_origin + t0*ray_direction but getting the normal vector is a bit of a pain because you don't get which side is hit. Morgan has been looking at methods where the surface normal comes with the hit. He'll publish that soon I think. But if it's not some huge speed bottleneck in your code, a bunch of ifs to find the face it works (the hitpoint will be on one of the faces).
ReplyDeleteThanks for sharing. Wouldn't tmax need multiplication by 1.00000024 as described in Thiago's 2013 paper "Robust BVH Ray Traversal"? Also, wouldn't arranging the code this way be more efficient since no swap is involved?
ReplyDeletefloat t0, t1;
...
if (invD >= 0.0f)
{
t0 = (min()[a] - r.origin()[a]) * invD;
t1 = (max()[a] - r.origin()[a]) * invD;
}
else
{
t1 = (min()[a] - r.origin()[a]) * invD;
t0 = (max()[a] - r.origin()[a]) * invD;
}
Good calls deadlock. But I would want to test your second selection empirically on any compiler/hardware combo I was on.
ReplyDeleteWhen I set the AABB with corners at (-1,-1,-1) and (1,1,1) and then attempt to test a ray at origin (-2,0,0) with direction (-1,0,0) this function returns true. Shouldn't this be a fail case? The ray origin is clearly outside the box, and its direction is looking away.
ReplyDeleteI feel like I'm cognitively not understanding the AABB.