Incremental mesh building

I now have a requirement: I need real-time ray intersection, but the number of mesh faces is growing in real time, which may increase by tens of thousands of faces per frame. The final mesh may be tens of millions in number.
How should I update the acceleration structure? I read in the Optix documentation that updating the tree requires keeping the same input size as when building the tree.
Maybe we should allocate a large enough memory in advance? And then keep overwriting the old vertex coordinates?

Hi @BilboGood, welcome!

In OptiX, there are two different BVH build modes: “build” (OPTIX_BUILD_OPERATION_BUILD) and “update” (OPTIX_BUILD_OPERATION_UPDATE).

The documentation you’re referring to is talking about the BVH build operation named “update”. Note how the word update is overloaded, and please keep in mind the distinction between the general question of how to update an acceleration structure, and the specific OptiX build operation named “update”.

OPTIX_BUILD_OPERATION_BUILD will always work. It is designed for all scenarios, and rebuilds the BVH from scratch. This can be a somewhat heavy operation since it needs to do spatial sorting of your primitives.

OPTIX_BUILD_OPERATION_UPDATE is designed for geometry that is moving or animated, but not changing topology. This is typically much faster than a full rebuild, because it skips the spatial sort and just updates the positions. This is a tradeoff because the traversal performance can degrade if the position update leads to greater spatial overlap of tree nodes.

If you need to add triangles to an existing GAS (Geometry Acceleration Structure), then your only choice is to use OPTIX_BUILD_OPERATION_BUILD. The build operation can handle hundreds of millions of triangles per second on current RTX GPUs. This might or might not be enough to handle tens of millions of triangles per frame, so you might need to be more selective with your GAS rebuilds, if you need real-time speeds.

If you want to create a new GAS and insert it into the larger tree under an IAS (Instance Acceleration Structure), then you can use OPTIX_BUILD_OPERATION_BUILD to build the new GAS, and use OPTIX_BUILD_OPERATION_UPDATE to update any existing GASes that have moved. After that you will need to use OPTIX_BUILD_OPERATION_BUILD to rebuild the IAS. This kind of strategy will allow updating more geometry in real-time than attempting to rebuild everything.

As for managing memory, it is a good idea to pre-allocate a large enough buffer, if you can. cudaMalloc can be slow, and if you need one or more new acceleration structures every frame, then putting them inside existing memory allocations will save time. This is easy if you only need to create new GASes, for example. It will be trickier if you want to both delete some GASes and create some new GASes every frame. In that case you’ll likely need a more sophisticated memory pool manager.

https://raytracing-docs.nvidia.com/optix8/guide/index.html#acceleration_structures#dynamic-updates


David.