Yes, changing the scene hierarchy is expensive.
If you experience issues when changing the scene hierachy, I would recommend to split the next launch into individual OptiX context validate(), compile(), and a dummy launch(0, 0, 0) in the debug case only to see where things broke.
Validate checks the scene and resources, compile builds the kernel in case there have been changes to programs (e.g. adding and removing material shaders), and the dummy launch builds the acceleration structures when necessary. The next real launch will then only render.
Always try the newest OptiX version in case of problems first.
If you have Transform nodes anyway, setting them to a null scale or very tiny and somewhere invisible is actually the fastest thing you can do to toggle sub-trees without changing the scene hierarchy as you’ve found out.
The Selector node is an elegant solution to toggle children in the scene, though it costs a little due to the additional hierarchy level.
We’ve used this in our scene graph in the past to implement Switch nodes which behave like a DIP-switch (any of many children) and for Flipbooks (one of many children).
Code for the visit programs of these two options can look like this:
rtBuffer<unsigned int> indexBuffer;
RT_PROGRAM void visit_switch()
size_t numIndices = indexBuffer.size();
for ( size_t i = 0; i < numIndices; ++i )
rtIntersectChild( indexBuffer[i] );
rtDeclareVariable( unsigned int, flipbookIndex, , );
RT_PROGRAM void visit_flipbook()
rtIntersectChild( flipbookIndex );
In the Switch visit program the indexBuffer contains the zero based indices of the children which are active. In the Flipbook visit program it’s just the one index variable.
Another method to toggle the visibility would be during the rendering by letting the anyhit program ignore all hits. Though this still costs the same intersection and anyhit program time, you just omit the closesthit program invocation.
We’ve used that to be able to independently toggle the visibility of objects in reflections, refractions, and shadows.