UsdSuperLayer ************ |sparkles| **New in Katana 8.5** Introduction ============ The :kat:node:`UsdSuperLayer` node type is a new base SuperTool node type whose underlying type is the :py:class:`UsdLayerSuperTool ` class. This SuperTool provides direct access to a USD Layer at the node graph level. The purpose is to use USD as its core source of truth, with parameters serving as UI elements. This is fundamentally different to other node types in Katana where, typically, parameters store the recipe that define the node. This base node type is not intended to replace our typical, fully procedural node types, since some proceduralism is lost. However, for certain workflows, there is a significant gain in performance and usability. These are the derived node types that extend the :kat:node:`UsdSuperLayer` node type: - :kat:node:`UsdGaffer` The common interface for the node types that derive from :kat:node:`UsdSuperLayer`: .. autoclass:: NodesUsdAPI.UsdSuperLayer.UsdLayerSuperTool How to make your own SuperTool from :kat:node:`UsdSuperLayer` ============================================================= This section explains how to extend the :kat:node:`UsdSuperLayer` node type to construct your own SuperTool. The SuperTool plug-in consists of its module, its registration, its editor and its node. They are defined in Python files placed within a subdirectory named ``/SuperTools`` under the ``KATANA_RESOURCES`` path. This allows Katana to automatically pick up and load the plug-in during startup. First we need to register the new SuperTool as a plug-in. .. literalinclude:: ../../../PLUGINS/Resources/Examples/SuperTools/ExampleUsdSuperLayerSuperTool/__init__.py :caption: :download:`./__init__.py <../../../PLUGINS/Resources/Examples/SuperTools/ExampleUsdSuperLayerSuperTool/__init__.py>` :language: python Next we initialize the module for our SuperTool. We define a GetEditor function, which will return the Editor class for this node. .. literalinclude:: ../../../PLUGINS/Resources/Examples/SuperTools/ExampleUsdSuperLayerSuperTool/v1/__init__.py :caption: :download:`./v1/__init__.py <../../../PLUGINS/Resources/Examples/SuperTools/ExampleUsdSuperLayerSuperTool/v1/__init__.py>` :language: python Next we initialize our editor for the SuperTool, often containing functionality around the UI elements. .. literalinclude:: ../../../PLUGINS/Resources/Examples/SuperTools/ExampleUsdSuperLayerSuperTool/v1/Editor.py :caption: :download:`./v1/Editor.py <../../../PLUGINS/Resources/Examples/SuperTools/ExampleUsdSuperLayerSuperTool/v1/__init__.py>` :language: python Finally is the node for our SuperTool, this will contain functionality around parameters. .. literalinclude:: ../../../PLUGINS/Resources/Examples/SuperTools/ExampleUsdSuperLayerSuperTool/v1/Node.py :caption: :download:`./v1/Node.py <../../../PLUGINS/Resources/Examples/SuperTools/ExampleUsdSuperLayerSuperTool/v1/__init__.py>` :language: python Plug-ins ======== :kat:node:`UsdSuperLayer`-derived node types can be extended with various forms of Python plug-ins. Context Menu Plug-ins --------------------- Overview ^^^^^^^^ This section describes how to extend the available context menu actions in :kat:node:`UsdSuperLayer`-derived node types by registering ``UsdSuperLayerContextMenu`` plug-ins. These extensions are written in the form of :py:class:`ContextMenuPluginBase `-derived classes that are registered as regular Katana Python plug-ins. A ContextMenuPlugin is able to modify selected Prims in any way they wish so long as it affects the editable layer only. For example, this includes modifying in batch, bringing in entire sub-trees of prims, or creating new prims. In addition to registering and unregistering plug-ins from the plug-in registry, which can be done at runtime with the :py:class:`ContextMenuPluginRegistry ` Python API, it is also possible to temporarily deactivate without unregistering plug-ins from the system. The plug-in consists of a class and its registration, defined in a Python file placed within a subdirectory named ``/UIPlugins`` under the ``KATANA_RESOURCES`` path. This allows Katana to automatically pick up and load the plug-in during startup. To define the class, it must derive from :py:class:`ContextMenuPluginBase ` and implement the :py:meth:`menuPaths() ` and :py:meth:`callbackOnClick() ` class methods. .. code-block:: python class UsdSuperLayerSampleContextMenuPlugin(ContextMenuPluginBase): @classmethod def callbackOnClick( cls, menuPath: str, controller: usg.StageSubtreeController, selectedPrimPaths: usg.PathArray, node: UsdLayerSuperTool, editor: UsdSuperLayerEditor, ) -> bool: ... @classmethod def menuPaths(cls) -> list[str]: ... The :py:meth:`menuPaths() ` class method must return a list of menu paths. Each path string followed by forward slashes (``/``) will create a sub-menu. For example, a ``Add Prim/Rect Light`` entry will create a context menu :kat:ui:`Add Prim` and a sub menu under it called :kat:ui:`Rect Light`. The :py:meth:`callbackOnClick() ` class method is called when a user clicks on the corresponding menu action. If any modifications have been made at all to the editable layer, the function must return ``True``; if it failed to return the correct value, there may be issues where the node becomes out of sync with the changes which have been made. The base class also provides additional functions that can be overridden to further customize the ContextMenuPlugin: * :py:meth:`callbackPostClick() ` Optional callback best suited for post-processing tasks, such as selecting created prims (runs after `callbackOnClick`, only if it has returned `True`). * :py:meth:`shortcutKeys() ` returns ``QKeySequence`` for provided menu path, such as ``QKeySequence("Ctrl+A")``. * :py:meth:`tooltip() ` returns a tool tip message that will be displayed when a user hovers over the menu action. * :py:meth:`isVisible() ` returns a boolean to indicate whether the menu action should be visible. * :py:meth:`isEnabled() ` returns a boolean to indicate whether the menu action should be enabled. * :py:meth:`blocksNotifications() ` returns a boolean to indicate whether the menu action should be wrapped in an `SdfChangeBlock `_ stopping notifications to the stage from the layer. Documentation should be consulted before use. To register the defined class as a plug-in, a top-level, global variable called ``PluginRegistry`` must be defined in the Python module. The variable is a list of tuples, with each tuple containing plug-in definitions. For example: .. code-block:: python PluginRegistry = [ ( 'UsdSuperLayerContextMenu', 1, 'SampleContextMenuPlugin', ( UsdSuperLayerSampleContextMenuPlugin, {'priority': 0, 'active': False, 'appliedNodes': ['all']}, ), ), ] * ``UsdSuperLayerContextMenu`` is the plug-in type name. * ``1`` is the plug-in version. * ``SampleContextMenuPlugin`` is the unique plug-in name. A list of currently registered plug-in names can be found by querying the ContextMenuPlugin registry. * ``UsdSuperLayerSampleContextMenuPlugin`` is the class derived from the :py:class:`ContextMenuPluginBase ` class. * ``{'priority': 0, 'active': False, 'appliedNodes': ['all']}`` are plug-in options, which currently supports the following: * ``priority`` defines the order in which plug-ins of this type will be loaded, where 0 is the default. Lower values are higher priority, and thus will appear higher up in the created context menus. The priorities of the registered plug-ins can be checked via :py:meth:`ContextMenuPluginRegistry.getPriority() `. Here is an example script to check the priorities for UsdGaffer. .. code-block:: python from NodesUsdAPI.UsdSuperLayer import ContextMenuPlugin reg = ContextMenuPlugin.GetRegistry() for plugin in reg.getPluginsForNode("UsdGaffer"): pluginName = reg.getPluginName(plugin) print(f"{pluginName}: {reg.getPriority(pluginName)}") # This is a sample output, which could change in future versions of Katana. # AddLightContextMenuPlugin: 1000 # AddRigContextMenuPlugin: 1100 # AddScopeContextMenuPlugin: 1200 # ... * ``active`` defines whether the plug-in is initially active. The default value is ``True``. Plug-ins' active state can be changed at a later time via :py:meth:`ContextMenuPluginRegistry.setActive() `. * ``appliedNodes`` is a list of node type names. Node instances of these node types will get this plug-in applied. If ``all`` is included in the list, the plug-in is applied to all node types. Plug-ins' nodes list can be added to at a later time via :py:meth:`ParametersHandlerPluginRegistry.registerNodeToPlugin() `. .. code-block:: python from NodesUsdAPI.UsdSuperLayer import ContextMenuPlugin reg = ContextMenuPlugin.GetRegistry() print(reg.getNodesRegisteredToPlugin("AddRigContextMenuPlugin")) reg.unregisterNodeFromPlugin("AddRigContextMenuPlugin", "UsdGaffer") print(reg.getNodesRegisteredToPlugin("AddRigContextMenuPlugin")) reg.registerNodeToPlugin("AddRigContextMenuPlugin", "UsdGaffer") print(reg.getNodesRegisteredToPlugin("AddRigContextMenuPlugin")) # This is a sample output, which could change in future versions of Katana. # ['UsdGaffer', 'UsdSuperLayer'] # ['UsdSuperLayer'] # ['UsdGaffer', 'UsdSuperLayer'] # ... Examples ^^^^^^^^ .. literalinclude:: ../../../PLUGINS/Resources/Examples/UIPlugins/UsdSuperLayerSampleContextMenuPlugin.py :caption: :download:`UsdSuperLayerSampleContextMenuPlugin.py <../../../PLUGINS/Resources/Examples/UIPlugins/UsdSuperLayerSampleContextMenuPlugin.py>` :language: python API ^^^ .. autoclass:: NodesUsdAPI.UsdSuperLayer.ContextMenuPlugin.ContextMenuPluginBase .. autoclass:: NodesUsdAPI.UsdSuperLayer.ContextMenuPlugin.PluginRegistry.ContextMenuPluginRegistry :inherited-members: Parameters Handler Plug-ins --------------------------- Overview ^^^^^^^^ This section describes how extra parameters can be created with ``UsdSuperLayerParametersHandler`` plug-ins registered for :kat:node:`UsdSuperLayer`-derived node types. These extensions are written in the form of :py:class:`ParametersHandlerPluginBase `-derived classes that are registered as regular Katana Python plug-ins. A ParametersHandlerPlugin defines the parameters that are shown in the :kat:ui:`Parameters` tab when a target prim is selected; handling of parameter changes is implemented in the plug-in too: the plug-in can modify the USD Prim in the content layer. In addition to registering and unregistering plug-ins from the plug-in registry, which can be done at runtime with the :py:class:`ParametersHandlerPluginRegistry ` Python API, it is also possible to temporarily deactivate without unregistering plug-ins from the system. The plug-in consists of a class and its registration, defined in a Python file placed within a subdirectory named ``/Plugins`` under the ``KATANA_RESOURCES`` path. This allows Katana to automatically pick up and load the plug-in during startup. To define the class, it must derive from :py:class:`ParametersHandlerPluginBase ` and implement the :py:meth:`isPrimSupported() `, :py:meth:`buildOrUpdateParameters() `, and :py:meth:`onParameterChanged() ` class methods. .. code-block:: python class UsdSuperLayerExampleParametersHandlerPlugin(ParametersHandlerPluginBase): @classmethod def isPrimSupported( cls, node: NodegraphAPI.Node, primPath: str, usdPrim: usg.Prim | None, sdfPrim: usg.Prim | None, ) -> bool: ... @classmethod def buildOrUpdateParameters( cls, node: NodegraphAPI.Node, primPath: str, usdPrim: usg.Prim | None, sdfPrim: usg.Prim | None, groupParam: NodegraphAPI.Parameter, ) -> None: ... @classmethod def onParameterChanged( cls, node: NodegraphAPI.Node, primPath: str, sdfPrim: usg.Prim, groupParam: NodegraphAPI.Parameter, parameter: NodegraphAPI.Parameter, parameterSampleTime: float, usdSampleTime: float, ) -> bool: ... The :py:meth:`isPrimSupported() ` class method must return ``True`` to indicate that the target prim, as specified by the prim path argument, is to be managed by the plug-in. For example, the predicate can be based on the existence of a certain USD Schema applied in the prim. The :py:meth:`buildOrUpdateParameters() ` class method is called on prims that have been stated as *supported* by the :py:meth:`isPrimSupported() ` method. The method is in charge of defining (or updating) parameters for the target prim. The :py:meth:`onParameterChanged() ` class method is invoked when parameters previously created by the :py:meth:`buildOrUpdateParameters() ` method change. It gives the plug-in an opportunity to make persistent changes in the content layer from the :kat:node:`UsdSuperLayer`-derived node. To register the defined class as a plug-in, a top-level, global variable called ``PluginRegistry`` must be defined in the Python module. The variable is a list of tuples, with each tuple containing plug-in definitions. For example: .. code-block:: python PluginRegistry = [ ( 'UsdSuperLayerParametersHandler', 1, 'ExampleParametersHandlerPlugin', ( UsdSuperLayerExampleParametersHandlerPlugin, { 'active': True, 'priority': 0, 'appliedNodes': ['all'], }, ), ), ] * ``UsdSuperLayerParametersHandler`` is the plug-in type name. * ``1`` is the plug-in version. * ``ExampleParametersHandlerPlugin`` is the unique plug-in name. A list of currently registered plug-in names can be found by querying the ParametersHandlerPlugin registry. * ``UsdSuperLayerExampleParametersHandlerPlugin`` is the class derived from the :py:class:`ParametersHandlerPluginBase ` class. * ``{'active': True, 'priority': 0, 'appliedNodes': ['all']}`` are plug-in options, which currently supports the following: * ``active`` defines whether the plug-in is initially active. The default value is ``True``. Plug-ins' active state can be changed at a later time via :py:meth:`ParametersHandlerPluginRegistry.setActive() `. * ``priority`` defines the order in which plug-ins of this type will be loaded, where 0 is the default. Lower values are higher priority, and thus will appear higher up in the parameter list in the UI. * ``appliedNodes`` is a list of node type names. The plug-in will apply to node instances of the given node type(s). If ``all`` is included in the list, the plug-in is applied to all node types. Plug-ins' nodes list can be added to at a later time via :py:meth:`ParametersHandlerPluginRegistry.registerNodeToPlugin() `. Examples ^^^^^^^^ .. literalinclude:: ../../../PLUGINS/Resources/Examples/Plugins/UsdSuperLayerExampleParametersHandlerPlugin.py :caption: :download:`UsdSuperLayerExampleParametersHandlerPlugin.py <../../../PLUGINS/Resources/Examples/Plugins/UsdSuperLayerExampleParametersHandlerPlugin.py>` :language: python API ^^^ .. autoclass:: NodesUsdAPI.UsdSuperLayer.ParametersHandlerPlugin.ParametersHandlerPluginBase .. autoclass:: NodesUsdAPI.UsdSuperLayer.ParametersHandlerPlugin.PluginRegistry.ParametersHandlerPluginRegistry :inherited-members: .. |sparkles| unicode:: U+2728