Node Visibility

From K-3D

Jump to: navigation, search


Currently, the render engine plugins in K-3D (OpenGL, RenderMan, and Yafray) render a document by iterating over every node in the document, querying each node for the appropriate render-engine-specific interface, and if the node implements that interface, calling the appropriate method(s). In the OpenGL and RenderMan cases, the node is then responsible for rendering itself, using APIs appropriate to the render engine.

Because nodes (usually) render themselves, they have the option of doing nothing when called. Nodes have visibility properties that they test before rendering themselves - in most cases, several visibility properties, one for each type of render engine. In the case of the RenderMan engine, nodes have two visibility-related properties, one controlling visibility of the object in the final rendered frame, and one controlling visibility of the object when generating shadow maps.

Although this system is easy to understand and straightforward to implement, it has many drawbacks:

  • Each render pass iterates over all N document nodes instead of (the ideal) M visible nodes. The difference may be significant, particularly during interactive rendering, since time is wasted querying nodes that either aren't renderable at all, aren't renderable by that particular render engine, or aren't currently visible.
  • Redundant dynamic casts - the work performed to query each node for a rendering interface is performed for every render pass. This is repetitive, potentially expensive, and may have a significant impact during interactive rendering.
  • Users pay for what they don't use - the visibility flags in renderable nodes consume memory, CPU cycles, and disk space whether they're ever used by the user or not.
  • Can't handle multiple render engine types - adding one-or-more visibility flags for every type of render engine added to the system will not scale for two reasons:
    • A long laundry-list of visibility flags becomes unusable for users (and exacerbates the problem of paying for what they don't use).
    • Adding a new render engine type means touching (even if only through a base class) every drawable node in the system.
  • Can't handle multiple render passes - in the general case, users will need to control the visibility of renderable nodes on a per-render-pass (i.e. per-render-engine) basis. The current visibility flags cannot be extended to this case.


Maintain lists of renderable nodes on a per-render-engine basis. This makes it possible to:

  • Control visibility on a per-render-engine basis, by simply adding/removing nodes from each render engine's list of nodes-to-be rendered.
  • Improve performance in multiple ways:
    • Render engines only have to iterate over their individual list of visible nodes, rather than every node in the document.
    • Render engines no longer have to query nodes for render interfaces during each render pass, their internal list of visible nodes can already contain the correct interface types.
  • Improve scalability in functionality - a suitably-smart user interface layer should be able to control node visibility for new render engine types without any coding.
  • Support for multi-pass rendering - provides fine-grained control over which render engine(s) will render a given node.
  • Users don't pay for what they don't use - the overhead of multiple visibility properties per-node is eliminated.


  • Created k3d::inode_collection_property for properties that represent collections of nodes.
  • We currently use k3d::inode_collection_property properties to store visible nodes and enabled lights for both RenderManEngine and YafrayEngine.
  • We need to implement a similar approach for OpenGLEngine.

Future Work

  • Per Render Engine Painters extends this work so that nodes can control visibility / appearance to an even finer granularity.
  • If we want to control node visibility through the pipeline, we can create a special-purpose node that acts as a source/modifier of inode_collection_property values.