Search Tips

Search is based on keyword.

`Ex: "Procedures"`

Do not search with natural language

`Ex: "How do I write a new procedure?"`

Give Feedback Support Portal

# Q100311: Implementing Live Rendering in a renderer plug-in

Warning: This article contains links to external websites

#### SUMMARY

This article explains how Live Rendering can be implemented in a renderer plug-in and covers the following topics:

- Attribute Convention
- RendererInfo Plug-in functions
- Render Plug-in functions
- Python Utilities
  - LiveRenderAPI
  - LiveRenderActions
  - Callbacks
- Gotchas
  - Single Sampled Updates
  - Non persistent updates

For a general explanation of LiveRendering, please find a description of it in the Katana Online Help section on Render Types, as well as see the Starting and Stopping Live Rendering sub-section of Performing a Render, and the section on Controlling Live Rendering.

A detailed description of other parts of renderer plug-ins, and documentation of other functions of the RenderAPI that are not directly related to LiveRendering can be found in the Renderer Plug-ins section of the Katana Developer Guide.

####

#### MORE INFORMATION

# Attribute Convention

Katana’s Live Rendering system is powered by attributes in the scene graph. In the name of efficiency, only the attributes that are required to update the renderer are sent to the render plug-in. There is an attribute convention to determine which attributes these are, which is as follows:

liveRender.<updateGroup>.<attributeName>

<updateGroup> - This is a GroupAttribute that is used to group attributes together into a single update.

<attributeName>- This is the name of the top-level attribute to monitor. In the image above the liveRender.geoXform.xform attribute is instructing the live render system to send any changes to the top-level xform attribute. Note that this is a StringAttribute whose value usually matches the updateGroup this is for legacy reasons, but is not generally used internally. If multiple attributes are specified in the same update group they will all be sent to the renderer when ever any one of them changes.

# RendererInfo Plug-in functions

    void fillLiveRenderTerminalOps(OpDefinitionQueue& terminalOps,
      const FnAttribute::GroupAttribute& stateArgs)

While it is possible to set up the above attribute convention in the Node Graph, it is typically more useful to use the fillLiveRenderTerminalOps() function in the RendererInfo plug-in to set up the attributes automatically when the Live Render starts. The function is passed an argument called terminalOps that is a std::deque that contains none or more std::pair objects containing the op type (as a std::string), and the op arguments (as a GroupAttribute).

Eg.The below code monitors changes in the xform attribute of light locations below /root/world/lgt.

    FnAttribute::GroupBuilder opArgs;
    opArgs.set("type", FnAttribute::StringAttribute("light"));
    opArgs.set("location", FnAttribute::StringAttribute("/root/world/lgt"));
    opArgs.set("attributeNames", FnAttribute::StringAttribute("xform"));
    terminalOps.push_back(std::make_pair("LiveRenderFilter", opArgs.build()));

There are several Geolib3 Ops that ship with Katana that are useful here:

LiveRenderFilter Used to indicate which attributes should be monitored for live rendering. Multiple attributes can be monitored by a single LiveRenderFilter and will all be sent as a single GroupAttribute should any of them change. This is the standard way of setting up the liveRender attribute convention described above.
OpArgs - attributeNames (StringAttribute) - The names of attributes should should be monitored for changes and sent to the render plug-in as a single update whenever one changes. - location(StringAttribute) - A CEL expression defining the first location where this op applies. It will then be applied at all child locations. - exclusions(StringAttribute) - (Optional) A list of excluded location types, where this op should not run. - typeAlias(StringAttribute) - (Optional) A name for the 'type' attribute that will be sent to the render plug-in. If not set the location type will be used instead. - type(StringAttribute) - (Optional) If set, the op will only run at locations of this type. - collectUpstream(IntAttribute) - (Optional) If non-zero the values of each monitored attribute at each parent location will also be included in the live render update.

LiveAttribute This op stores the values that are being generated by viewer manipulators during a manipulation (as opposed to waiting for the manipulation to be completed and the parameter finalized). This op is a special case that is looked for specifically by the Live Rendering module.
OpArgs The args for this op are set automatically by the Live Render system and should not be set manually.

LocalizeXform Flattens the xforms of a location from all of its ancestors into a single world-space matrix called xform.matrix.
OpArgs - excludeCel(StringAttribute) - A CEL expression describing the scene graph locations that the op should not apply to. - addMaterialHash(IntAttribute) - (Optional) Legacy behaviour for older version of live rendering. If non-zero, the hashed value of the 'material' attribute will be stored as 'materialHash'. - outputAttrName(StringAttribute) - (Optional) The name to use to store the new local xform attributes. Defaults to 'xform', overwriting the existing attribute.

LocalizeLiveAttributeXform During manipulation in the viewer the actual xform attribute of the location doesn't change (until pen-up). Instead the LiveAttribute op is used to store the temporary xform under liveAttributes.xform. This op works like localizeXform, but is aware of this liveAttribute convention, so if liveAttributes.xform will be used instead of xform if it exists. This allows the locations xform to be updated during manipulation. Naturally this op must be applied after the LiveAttribute op.
OpArgs - addMaterialHash(IntAttribute) - (Optional) Legacy behaviour for older version of live rendering. If non-zero, the hashed value of the 'material' attribute will be stored as 'materialHash'.

LocalizeLightListLiveRenderFilter This Op is a specialization of the standard LiveRenderFilter op specifically for use with light lists. It behaves similarly to the LiveRenderFilter op except that it will create additional information about the lightList attribute at each location. This information includes the path to the light, whether light linking is enabled for the current location, and whether it is enabled at the parent location. This information will be sent to the render plugin as a "lightLink" update.
OpArgs - attributeNames(StringAttribute) - The names of attributes should should be monitored for changes and sent to the render plug-in as a single update whenever one changes. - location(StringAttribute) - A CEL expression defining the first location where this op applies. It will then be applied at all child locations. - exclusions(StringAttribute) - (Optional) A list of excluded location types, where this op should not run. - typeAlias(StringAttribute) - (Optional) A name for the 'type' attribute that will be sent to the render plug-in. If not set the location type will be used instead. - type(StringAttribute) - (Optional) If set, the op will only run at locations of this type. - collectUpstream(IntAttribute) - (Optional) If non-zero the values of each monitored attribute at each parent location will also be included in the live render update.

CoordinateSystemLiveRenderFilter This is another specialization of the standard LiveRenderFilter op. It is for use with coordinate systems. It behaves identically to LiveRenderFilter op except that it will first check whether the current location is listed in the globals.coordinatesystems attribute at /root/world/ and only continue execution if that is true.
OpArgs - attributeNames(StringAttribute) - The names of attributes should should be monitored for changes and sent to the render plug-in as a single update whenever one changes. - location(StringAttribute) - A CEL expression defining the first location where this op applies. It will then be applied at all child locations. - exclusions(StringAttribute) - (Optional) A list of excluded location types, where this op should not run. - typeAlias(StringAttribute) - (Optional) A name for the 'type' attribute that will be sent to the render plug-in. If not set the location type will be used instead. - type(StringAttribute) - (Optional) If set, the op will only run at locations of this type. - collectUpstream(IntAttribute) - (Optional) If non-zero the values of each monitored attribute at each parent location will also be included in the live render update.

# Renderer Plug-in functions

    int startLiveEditing()

    int stopLiveEditing()

These two functions are called from Katana to notify you of when live rendering is active and that updates to locations should be expected

    int processControlCommand(const std::string & command)

This function is a method of communication from the Katana UI to the render plug-in. The UI can send a command as a string via the python LiveRenderAPI.SendCommand() function, which you can handle in the render plug-in for whatever purpose you desire.

    int queueDataUpdates(FnAttribute::GroupAttribute updateAttribute)

When a monitored attribute changes, it’s new value will be passed to the render plug-in via this function. The passed attribute will contain three child attributes:

- type - The type of update (this is the <updateGroup> listed above in the attribute convention section)
- location - The scene graph location that this update is for.
- attributes - The value of the changed attributes. Note that if the location has been deleted, this will contain an attribute named deleted

Note that this function is called in a dedicated thread that is exclusively for the receiving of live render updates.

    bool hasPendingDataUpdates()

This function tells the renderboot process whether there are live render updates that have been queued in queueDataUpdates() that should be applied.

    int applyPendingDataUpdates()

This function is called in the main render thread and should take any queued live updates and actually apply them. It is only called if hasPendingDataUpdates() returns true.

# Python Utilities

Katana’s UI has several utilities to help improve the Live Rendering experience, presented below:

## LiveRenderAPI

This API allows you to send a custom command (string) or live update to the running live render with the LiveRenderAPI.SendCommand() and LiveRenderAPI.SendData() functions. It also has various functions to query and modify the list of terminal ops that are being used by the Live render subsystem. These terminal ops are used to determine when a location is changed, rather than cause changes to the current scene graph (as generated by your nodes). This is effectively a way to change the ops that were passed during the call to RendererInfo::fillLiveRenderTerminalOps().

## LiveRenderActions

It is possible to extend the Render > Live Rendering menu with your own custom menu items through the use of the class in plugin_apis/python/BaseLiveRenderAction.py. Simply derive from the BaseLiverRenderAction class (which itself is derived from QtGui.QAction) and override the member functions. Your class can then make use of any of Katana’s python APIs, including the LiveRenderAPI, allowing it to send custom commands or updates to the render plug-in. Instances of LiveRenderActions should be placed in a KATANA_RESOURCEs/UIPlugins directory to ensure they only attempt to load during UI sessions.

## Callbacks

Before sending either a live update or a live render command to the render plug-in the Katana will trigger a callback named onLiveRenderUpdate or onLiveRenderCommand respectively. These callbacks will be passed the command or update attribute that is about to be passed to the render plug-in. This is primarily for monitoring purposes, allowing you to inspect the data that is being passed to the render plug-in but it is also possible to prevent the message from being sent by raising an exception. This however will trigger an error message in Katana’s Message log.

# Gotchas

## Single Sampled Updates

When a render starts geolib generates multi-sampled attributes to allow for motion blur etc. However in the Katana UI, attributes are generally only retrieved using a single sample and the Live Render updates come from the Katana UI. This means that attributes that are sent during a live update generally only have a single time sample.

## Non persistent updates

When a render starts, the op tree to generate the scene is written to disk by Katana and read by the render process, which uses its own Geolib3 runtime. The render plug-in is given access to a SceneGraphIterator to query the scene graph and its attributes. This scene however is immutable. When a live render update is passed from Katana it cannot update the Geolib3 runtime. This means that the SceneGraphIterators will always return the original scene, even if live updates have been received by the render plug-in. It is therefore a requirement that live update attributes contain all of the information that the render plug-in needs, as you cannot safely use a SceneGraphIterator to get additional information.