In this final segment for the first rayracing lecture, we're going
to consider optimizations and acceleration.
Testing each object for each ray is slow. This is one of the causes
why raytracing has historically been slow.
One can therefor consider using fewer rays by adaptively sampling
which pixels to shoot a ray fo,r by having adaptive depth controls. One
could also consider generalized rays where you shoot multiple rays at
a time: things like beam tracing, cone tracing, pencil tracing and so
on.
Finally, one can consider faster intersections where one optimizes a
ray object intersection. So ray triangle intersections are very
optimized. Or, and this is where most of the acceleration work falls,
one can have fewer intersections.
We come to a rich area of raytracing known as acceleration structures,
where given a ray, you want to ensure that you test as few objects as
possible: ideally only the object the ray will hit. That's not possible
in practice but we can often consider the number of intersections to
be logarithmic in the total size of the number of objects.
So first we consider bounding boxes possibly hierarchically, so you
could have a bounding box for the whole scene, the bounding box for your
room, the bounding box for the various triangles in your room.
If the ray doesn't intersect the entire bounding box, and remember,
there are very efficient ray box intersection tests, then one needn't
check the individual objects within the bounding box. One can also
consider spatial hierarchies that organize these bounding boxes,
things like oct-trees, kd trees, BSP trees. BSP stands for binary
space partitioning. Octtree takes 3D space, cuts it along the center
for each axis of a cube, to break it into 8 octants.
Another acceleration structure is a grid. And so this could be a
regular grid or hierarchical grid as far as we're concerned we're
going to consider just a regular grid.
I trace my way through the grid.
So what I do is, I first go to the first grid cell.
And I see there's no intersection. Also, note that the traversal
through the grid might seem irregular, but in fact there are regular
intersection points along either of the two axes here, or three axes
in 3D, and so you can very simply and incrementally compute the
next intersection point in the next cell. So I go to the next cell and
each cell has a pointer to all of the objects that intersect that
cell. The next cell after that, the next cell after that, and now we
can see that I have an intersection, that
I need to test. So I need to test my ray against this object, but
it doesn't intersect. So I go to the next point. And if I implement
something like mailboxing, I know I've already tested against this
object, so I don't need to test again. Come down here.
Again I need to test against this object, no intersection, go forward.
And finally I have the object that I'm actually intersecting. One of
the interesting things to note is that the two objects on the side, so
this object and this object, were never tested against. There was no
need to actually even test them for intersection, and so a large part
of the space that is not in the traversal part actually need never be
tested for a ray surface intersection.
So regular grids are the simplest acceleration structure. So, for
example, a 5 by 5 by 5 grid. For each grid cell you store all the
overlapping triangles, you march the way along the grid, you need to
be careful in doing this efficiently and you test against each
triangle in the grid cell. There are of course more complicated
spatial data structures trees like kd-trees, octtrees, bsptrees or
you can use hierarchical bounding boxes.