`NodeTypeBuilder` ================= .. module:: Nodes3DAPI.NodeTypeBuilder .. autoclass:: NodeTypeBuilder Op Chain Interfaces ------------------- .. autoclass:: BaseOpChainInterface :exclude-members: FnAttribute, FnGeolib .. autoclass:: OpChainInterface .. autoclass:: ParametersOpChainInterface Migration Guide: Modifying Graph State -------------------------------------- Node types created with :py:class:`NodeTypeBuilder` could update local Graph State from within a :py:func:`buildOpChain` function registered with :py:meth:`setBuildOpChainFnc`. That mechanism, using :py:meth:`setExplicitInputRequestsEnabled`, is deprecated. Modifications to graph state made using explicit input requests are not visible to all parts of Katana. Some features like dimming nodes disabled due to local graph state; showing the local graph state in the UI; etc - do not work well with explicit input requests. Instead, nodes that make changes to local graph state should register a function with :py:meth:`setGetInputPortAndGraphStateFnc`. This function will be called to determine which of the nodes input Ports are active, and allows modifying the local graph state passed to the upstream node connected to the active inputs. For example, a node that sets a graph state variable like VariableSet, could be implemented with the deprecated explicit input request mechanism: .. code-block:: python # NOTE: Example using deprecated setExplicitInputRequestsEnabled from Katana import ( Nodes3DAPI, FnGeolibServices, FnAttribute ) def buildOpChain(self, interface): # Set an example attribute on all locations argsbuilder = FnGeolibServices.OpArgsBuilders.AttributeSet() argsbuilder.setCEL(FnAttribute.StringAttribute('//*')) argsbuilder.setAttr('info.example', FnAttribute.IntAttribute(1)) interface.appendOp('AttributeSet', argsbuilder.build()) # Get the graph state graphState = interface.getGraphState() # Get the parameters at the graphState's current time currentTime = graphState.getTime(); name = self.getParameter('name').getValue(currentTime) value = self.getParameter('value').getValue(currentTime) # Add a variable to the local graph state graphStateBuilder = graphState.edit() graphStateBuilder.setDynamicEntry('var:' + name, value) modifiedGraphState = graphStateBuilder.build() # Enable explicit input requests. This circumvents normal input # processing but allows modifying the local graph state. # DEPRECATED! interface.setExplicitInputRequestsEnabled(True) # Add the explicit input request for our input port with the modified graph state interface.addInputRequest('in', modifiedGraphState) # Define the parameter interface for nodes of our custom node type through a # builder for GroupAttribute objects, which is turned into a GroupAttribute # that is passed to the `setParametersTemplateAttr()` function on the # NodeTypeBuilder instance created below parametersTemplateAttrGroupBuilder = FnAttribute.GroupBuilder() parametersTemplateAttrGroupBuilder.set('name', 'myVariable') parametersTemplateAttrGroupBuilder.set('value', 'myValue') parametersTemplateAttr = parametersTemplateAttrGroupBuilder.build() # Create the node type using NodeTypeBuilder ntb = Nodes3DAPI.NodeTypeBuilder('MyVariableSet_Deprecated') ntb.setInputPortNames(('in',)) ntb.setParametersTemplateAttr(parametersTemplateAttr) ntb.setBuildOpChainFnc(buildOpChain) ntb.build() The deprecated example can be updated to use :py:meth:`setGetInputPortAndGraphStateFnc` with some minor changes: * Extract the code for modifying the graph state into a new function `getInputPortAndGraphState(self, outputPort, graphState)` * Remove the call to :py:meth:`interface.setExplicitInputRequestsEnabled` * Replace the call to :py:meth:`interface.addInputRequest` with a call through to the default implementation :py:meth:`Node3D.getInputPortAndGraphState` * Add a call to :py:meth:`NodeTypeBuilder.setGetInputPortAndGraphStateFnc` to register the new `getInputPortAndGraphState` function. .. code-block:: python # NOTE: Example using new getInputPortAndGraphState from Katana import ( Nodes3DAPI, FnGeolibServices, FnAttribute ) def buildOpChain(self, interface): # Set an example attribute on all locations argsbuilder = FnGeolibServices.OpArgsBuilders.AttributeSet() argsbuilder.setCEL(FnAttribute.StringAttribute('//*')) argsbuilder.setAttr('info.example', FnAttribute.IntAttribute(1)) interface.appendOp('AttributeSet', argsbuilder.build()) def getInputPortAndGraphState(self, outputPort, graphState): # Get the parameters at the graphState's current time currentTime = graphState.getTime(); name = self.getParameter('name').getValue(currentTime) value = self.getParameter('value').getValue(currentTime) # Add a variable to the local graph state graphStateBuilder = graphState.edit() graphStateBuilder.setDynamicEntry('var:' + name, value) modifiedGraphState = graphStateBuilder.build() # Call through to the default implementation of this function # with the modified graph state. return Nodes3DAPI.Node3D.getInputPortAndGraphState(self, outputPort, modifiedGraphState) # Define the parameter interface for nodes of our custom node type through a # builder for GroupAttribute objects, which is turned into a GroupAttribute # that is passed to the `setParametersTemplateAttr()` function on the # NodeTypeBuilder instance created below parametersTemplateAttrGroupBuilder = FnAttribute.GroupBuilder() parametersTemplateAttrGroupBuilder.set('name', 'myVariable') parametersTemplateAttrGroupBuilder.set('value', 'myValue') parametersTemplateAttr = parametersTemplateAttrGroupBuilder.build() # Create the node type using NodeTypeBuilder ntb = Nodes3DAPI.NodeTypeBuilder('MyVariableSet') ntb.setInputPortNames(('in',)) ntb.setParametersTemplateAttr(parametersTemplateAttr) ntb.setBuildOpChainFnc(buildOpChain) ntb.setGetInputPortAndGraphStateFnc(getInputPortAndGraphState) ntb.build()