Can a node have two parents?

Instead of a boolean, you could make it a frame number: if the frame number matches the current frame being rendered, you know it’s already been rendered, if it’s less, it still needs to be rendered. That prevents you from having to traverse all the nodes to clear it after each rendering.

If you have to render the scene multiple times from multiple points of view (eg. with shadows or reflections), a frame index wouldn’t do, and you would instead have to assign a global number that you increase every time Panda is about to traverse the scene for rendering.

As for instancing, that does break with this approach. It is not easy to determine the value of mayRenderMoreThanOnce, but the way to determine it would be to iterate the graph upwards until you find a node with more than one parent. However that means that in your use case it would return true, since that’s exactly what you’re telling Panda to do. I think what you really want is to prevent nodes from rendering multiple times with the same transform and state.

So what you could do is, instead of storing a “mayRenderMoreThanOnce” flag, store the accumulated transform and render state of that node in a variable when the traversal gets to it. Then the next time the traverser encounters it, it can check whether it matches the state of the last time you rendered that object, and if so, skip it.

A completely different approach to doing all this would be after traversal, by adding code to the relevant CullBin* classes to filter out duplicate CullableObject entries from the lists during sorting. Alternatively, one could change the CullBin*::add_object calls to check whether the object already exists with these parameters before adding it to the list of objects to draw.

This does add additional overhead, of course. However since CullBinStateSorted is the most commonly used bin, and it already sorts the results, it might be simply a matter of checking in draw() whether the object matches the properties of the previous one, and skip it if that’s the case. Or, switching it to an inherently sorted and uniquifying container like pset or ov_set.