Jacco Bikker has recently made an open source BVH creation and traversal library called TinyBVH available. He provides the C++ code and some example OpenCL code for GPU traversal. I had a very easy time porting the GPU side traversal code to OpenGL/GLSL, and have been able to use it to represent geometry in Icarus.
BVHs are a hierarchical structure for representing scene geometry, and provide much better scaling than the explicit primitive list in Siren and Daedalus. In these projects, the performance scaled linearly and became unusably slow around a couple, maybe low tens of thousands of primitives. Here, I've had success with scenes containing more than 10 million primitives.
PLY is a format for representing geometry data in a way similar to the Wavefront OBJ. It starts with a header defining the structure of e.g. a vertex, a triangle, etc, and then has a list of data that matches this format. It is very commonly used for point cloud data storage, where you need to keep position and color. Interfacing with this format is made very simple with the assistance of a library called hapPLY. Only part that required manual inspection is the specific naming of the property arrays, as they are specified as strings in the PLY format itself.
There are some projects designed for large-scale visualization of point cloud data like this, like potree. It's important data for GIS applications, for example, when specific geometry is needed for a landscape or building. Anecdotally, I've also heard that this is used in industry for things like measuring the volume of a pile of gravel or other materials that might otherwise be difficult to estimate. I was able to find quite a few example PLY files on Sketchfab, and had a lot of success loading and visualizing them in Icarus.
Another really good piece of software, especially since PLY is not the only format you will find this data in, is called CloudCompare. I've mostly used it for format conversions from .asc and .las, but it has an enormous amount of GIS-oriented features.
I really like the way I did this. Starting with the observation that after the very first preprocessing step of calculating the bounding boxes for the model's triangles... and then as a separate, later step, it uploads both the buffer with the BVH nodes and the buffer with the geometry data. I wanted to kind of hack it such that leaf nodes were small spheres, instead of triangles. So my process looks like this:
And it requires no other modifications. The sphere indexing that comes from the BVH node traversal works exactly as the triangle indexing does. I was very pleased with how smoothly that went. A sphere at every point location specified by the PLY file is an interesting way to visualize the data, especially when those spheres are treated as a colored glass material. Some of the files had more than 10 million points, and even at that scale, the performance was extremely impressive.
I have also really enjoyed TinyBVH for this hall-of-mirrors usage, where you position the camera inside of a mesh and treat it as a mirror or glass material. This kind of kalideoscopic, psychedelic usage is really compelling, and you can spend a lot of time lining up camera angles. I do have a bug where some intersectors show through others, especially on primary rays... I'm not sure why that is. Will require some debugging.
I think this method could extend to arbitrary primitives, very much like what I had in the primitive list in Siren and Daedalus. Specifying the interseciton primitive, position, and orientation requires a bit more data than I used here. Doing it out on paper, I think I can fit most everything in 64 floats per primitive. What's nice is that scaling this up is not going to affect ray performance as much as changes to the BVH nodes themselves would. The actual ray-primitive tests are much rarer than the ray-box tests of the bounding boxes, and only load this data out of the SSBO when the ray reaches that leaf node. Oriented polyhedra like cubes could potentially create small specularities that could be really interesting at this scale.
I've also been messing with a line renderer. One of the applications for it, I want to use as a ray debugger. Basically, I want to be able to pull the ray data out of GPU memory and visualize it as a set of lines. The idea is that a tool like this helps identify situations like this bug I'm having with surfaces being visible when they should not. There's an occluding surface, which is not being taken over the more distant surface. For some reason, it goes away with some combinations of active intersectors... it's not clear to me where the bug is coming from at this point.
Last updated 2/9/2025