GeometryInstances - toggling objects between visible / invisible

Ironically, one of the most trivial aspects of scene management has been a constant thorn. I’ve tried several approaches

Add/Remove child from parent ( both as a packed array, inc/dec child count and using null slots)
Replacing self in parent with a dummy node, and various combinations of

I haven’t tried using a selector node.

Finally ( a hack ) have started setting the transform to a position outside the camera frustrum. And this has shown the best performance, and least issues. However lately, we’ve been experiencing some odd crashes if we try to update objects outside the view frustrum.

Needless to say, I could simply have bugs somewhere. But the question remains, what is the correct way to handle setting instance visible / invisible. PrimCount won’t work, as it would affect all instances.

Thanks,

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.

Many thanks,
I’m going to continue with scale = tiny amount or offscreen.
I do split up the compile steps, but this has inspired me to specifically

#ifdef DEBUG
split and report for each errors + timings
#elif defined PROFILE
split and report for each timings
#else
single launch
#endif