Katana Layered Menu
Default Layered menu
The very basic documentation of how to set up your personalized layered menu inside katana is provided by Foundry. Here is one example that was included in the Katana_2.1v5 Technical Guide.
https://thefoundry.s3.amazonaws.com/products/katana/releases/2.1v5/Katana_2.1v5_TechnicalGuide.pdf
""" Example script that registers a layered menu for the B{Node Graph} tab, which shows the names of available PRMan shaders and creates a PrmanShadingNode node with the chosen shader set on it when one of the menu entries is chosen. """ from Katana import NodegraphAPI, RenderingAPI, LayeredMenuAPI from RenderingAPI import RenderPlugins def PopulateCallback(layeredMenu): """ Callback for the layered menu, which adds entries to the given C{layeredMenu} based on the available PRMan shaders. @type layeredMenu: L{LayeredMenuAPI.LayeredMenu} @param layeredMenu: The layered menu to add entries to. """ # Obtain a list of names of available PRMan shaders from the PRMan renderer # info plug-in rendererInfoPlugin = RenderPlugins.GetInfoPlugin('prman') shaderType = RenderingAPI.RendererInfo.kRendererObjectTypeShader shaderNames = rendererInfoPlugin.getRendererObjectNames(shaderType) # Iterate over the names of shaders and add a menu entry for each of them # to the given layered menu, using a green-ish color for shaderName in shaderNames: layeredMenu.addEntry(shaderName, text=shaderName, color=(0.3, 0.7, 0.3)) def ActionCallback(value): """ CUSTOM NODE GRAPH MENUS | CREATING A CUSTOM NODE GRAPH MENU PLUG-IN TECHNICAL GUIDE 159 Callback for the layered menu, which creates a PrmanShadingNode node and sets its B{nodeType} parameter to the given C{value}, which is the name of a PRMan shader as set for the menu entry in L{PopulateCallback()}. @type value: C{str} @rtype: C{object} @param value: An arbitrary object that the menu entry that was chosen represents. In our case here, this is the name of a PRMan shader as passed to the L{LayeredMenuAPI.LayeredMenu.addEntry()} function in L{PopulateCallback()}. @return: An arbitrary object. In our case here, we return the created PrmanShadingNode node, which is then placed in the B{Node Graph} tab because it is a L{NodegraphAPI.Node} instance. """ # Create the node, set its shader, and set the name with the shader name node = NodegraphAPI.CreateNode('PrmanShadingNode') node.getParameter('nodeType').setValue(value, 0) node.setName(value) node.getParameter('name').setValue(node.getName(), 0) return node # Create and register a layered menu using the above callbacks layeredMenu = LayeredMenuAPI.LayeredMenu(PopulateCallback, ActionCallback, 'Alt+P', alwaysPopulate=False, onlyMatchWordStart=False) LayeredMenuAPI.RegisterLayeredMenu(layeredMenu, 'PrmanShaders')
Let’s see what each part is doing:
"""
Example script that registers a layered menu for the B{Node Graph} tab, which
shows the names of available PRMan shaders and creates a PrmanShadingNode node
with the chosen shader set on it when one of the menu entries is chosen.
"""
This part is just an introductory comment, you can identify it by the triple quotations that precede and close the paragraph (“““ “““).
from Katana import NodegraphAPI, RenderingAPI, LayeredMenuAPI
from RenderingAPI import RenderPlugins
Here we are importing all the necessary modules for all the functions to work. You might need your own modules depending what you hope to achieve within your menu.
def PopulateCallback(layeredMenu): """ Callback for the layered menu, which adds entries to the given C{layeredMenu} based on the available PRMan shaders. @type layeredMenu: L{LayeredMenuAPI.LayeredMenu} @param layeredMenu: The layered menu to add entries to. """ # Obtain a list of names of available PRMan shaders from the PRMan renderer # info plug-in rendererInfoPlugin = RenderPlugins.GetInfoPlugin('prman') shaderType = RenderingAPI.RendererInfo.kRendererObjectTypeShader shaderNames = rendererInfoPlugin.getRendererObjectNames(shaderType) # Iterate over the names of shaders and add a menu entry for each of them # to the given layered menu, using a green-ish color for shaderName in shaderNames: layeredMenu.addEntry(shaderName, text=shaderName, color=(0.3, 0.7, 0.3))
Now we encounter the first of 2 functions necessary for the menu to run. immediately we see a comment that describes the function. This particular menu will be driven by the available PRMan shaders. However, you can have a menu that is generated automatically or you can populate the entries manually. (Example later)
def ActionCallback(value): """ CUSTOM NODE GRAPH MENUS | CREATING A CUSTOM NODE GRAPH MENU PLUG-IN TECHNICAL GUIDE 159 Callback for the layered menu, which creates a PrmanShadingNode node and sets its B{nodeType} parameter to the given C{value}, which is the name of a PRMan shader as set for the menu entry in L{PopulateCallback()}. @type value: C{str} @rtype: C{object} @param value: An arbitrary object that the menu entry that was chosen represents. In our case here, this is the name of a PRMan shader as passed to the L{LayeredMenuAPI.LayeredMenu.addEntry()} function in L{PopulateCallback()}. @return: An arbitrary object. In our case here, we return the created PrmanShadingNode node, which is then placed in the B{Node Graph} tab because it is a L{NodegraphAPI.Node} instance. """ # Create the node, set its shader, and set the name with the shader name node = NodegraphAPI.CreateNode('PrmanShadingNode') node.getParameter('nodeType').setValue(value, 0) node.setName(value) node.getParameter('name').setValue(node.getName(), 0) return node
This second function takes whatever value is selected by the user in the displayed layered menu and executes a pre-determined action. In the default script, that action is associating the PRMan shader with a shader node, creating that node in the NodeGraph and then returning the node information back.
# Create and register a layered menu using the above callbacks layeredMenu = LayeredMenuAPI.LayeredMenu(PopulateCallback, ActionCallback, 'Alt+P', alwaysPopulate=False, onlyMatchWordStart=False) LayeredMenuAPI.RegisterLayeredMenu(layeredMenu, 'PrmanShaders')
This block also starts with a comment that describes what the next few lines are. This comment uses the ‘#’ symbol to declare the comment, which is used for a single line comment.
What is happening next is that the functions that we created before are initiated with pre-defined Katana processes. This are available to us because we imported the specific modules needed at the top of the script. The first one creates the layeredMenu element, with the parameters:
PopulateCalback- Function that generates menu entries
ActionCallback- Function that triggers once the user has selected an entry
‘Alt + P’ - Keyboard shortcut that will bring out the menu in the Node Graph.
alwaysPopulate - The option to rerun the initial parameters of the populate function every time the menu is called. If set to false, this process runs once on the first call and becomes cached during your session.
onlyMatchWordStart - This defines if the user keyboard input will try to match a menu entry starting at the beggining of the value name when True, or in any part of the name when False
The sample script contains only these parameters but there are more available to use depending the needs of your specific menu.
You can read more here:
https://learn.foundry.com/katana/dev-guide/Scripting/CustomizingUserInterface/LayeredMenu.html
The example provided by Foundry is displaying the shaders included in the Renderman plugin:
rendererInfoPlugin = RenderPlugins.GetInfoPlugin('prman')
shaderType = RenderingAPI.RendererInfo.kRendererObjectTypeShader
shaderNames = rendererInfoPlugin.getRendererObjectNames(shaderType)
If you do not have Renderman installed, your Layered Menu will show up empty.
Let’s see how you would add your own values and functions to the menu.