Example Scripts =============== These examples show Python scripts can be used to create and modify nodes in Katana. Examples of the use of these scripts include: - Shelf scripts to automate common operations in the UI. - Scripts to run at the command line using ``katana --script`` to create Katana node graph procedurally, and modify existing Katana projects. - Python commands to run in the interactive Python tab in the Katana UI. - Python commands to run in a command line shell using ``katana --shell``. Examples of the types of operations you can do with these scripts include: - Creating new nodes, and connect output ports of nodes to input ports of other nodes. - Set parameter values on nodes, including creating expressions on parameters. - Find all the nodes of a given type. - Load and save Katana projects. - Set off renders. You can look at the Python code for any existing shelf script. Right-click on the shelf script to bring up its properties. It is often easiest to create a custom user script, with the command ``execfile("/tmp/foo.py")``. Each time you execute the script, the file will be executed. Running Katana in script mode ----------------------------- General syntax: .. code-block:: sh $ katana --script myScript.py Passing arguments to a script: .. code-block:: sh $ katana --script myScript.py arg1 arg2 arg3 Inside the script the arguments can be interrogated as regular Python command-line arguments: .. code-block:: python import sys arg1 = sys.argv[1] arg2 = sys.argv[2] arg3 = sys.argv[3] Nodegraph & Parameters ---------------------- Create a new node .. code-block:: python from Katana import NodegraphAPI # Create a new node, as a child of root myNode = NodegraphAPI.CreateNode('CameraCreate', NodegraphAPI.GetRootNode()) # Name the node myNode.setName('myCamera') Copy a node .. code-block:: python from Katana import NodegraphAPI from Katana import KatanaFile # Find the node you want to copy sourceNode = NodegraphAPI.GetNode('NameOfMySourceNode') # To copy the node, Katana needs the node's XML (for efficiency, as an XmlIO element tree) xmlNode = NodegraphAPI.BuildNodesXmlIO([sourceNode]) # Create the copy as child of the root node # The 'Paste' function returns a list, since we're only asking for one node we grab the first element newNode = KatanaFile.Paste(xmlNode, NodegraphAPI.GetRootNode())[0] myNode.setName('myCamera') Set parameters on a node .. code-block:: python from Katana import NodegraphAPI # Create a node myNode = NodegraphAPI.CreateNode('CameraCreate', NodegraphAPI.GetRootNode()) myNode.setName('TestCam') # Set a string parameter myNode.getParameter('name').setValue('/root/world/cam/testcam', 0) # Set a float parameter myNode.getParameter('fov').setValue(55.0, 0) # Set children of a group parameter myNode.getParameter('transform.translate.x').setValue(100.0, 0) myNode.getParameter('transform.translate.y').setValue(200.0, 0) myNode.getParameter('transform.translate.z').setValue(300.0, 0) Create a simple renderable scene procedurally and save it to disk .. code-block:: python from Katana import NodegraphAPI from Katana import KatanaFile print "starting to create scene /tmp/pink_pony.katana" cameraCreateNode = NodegraphAPI.CreateNode('CameraCreate', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(cameraCreateNode, (100,400)) cameraCreateNode.getParameter('transform.translate.x').setValue(14, 0) cameraCreateNode.getParameter('transform.translate.y').setValue(18, 0) cameraCreateNode.getParameter('transform.translate.z').setValue(16, 0) cameraCreateNode.getParameter('transform.rotate.x').setValue(-18, 0) cameraCreateNode.getParameter('transform.rotate.y').setValue(53, 0) cameraCreateNode.getParameter('transform.rotate.z').setValue(0, 0) ponyCreateNode = NodegraphAPI.CreateNode('PonyCreate', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(ponyCreateNode, (300,500)) materialNode = NodegraphAPI.CreateNode('Material', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(materialNode, (300,400)) materialNode.getParameter('name').setValue('pink_mat', 0) materialNode.getParameter('namespace').setValue('geo', 0) materialNode.addShaderType('prmanSurface') materialNode.checkDynamicParameters() materialNode.getParameter('shaders.prmanSurfaceShader.enable').setValue(1, 0) materialNode.getParameter('shaders.prmanSurfaceShader.value').setValue('KatanaPhong', 0) materialNode.checkDynamicParameters() materialNode.getParameter('shaders.prmanSurfaceParams.Ks.enable').setValue(1, 0) materialNode.getParameter('shaders.prmanSurfaceParams.Ks.value').setValue(0.7, 0) materialNode.getParameter('shaders.prmanSurfaceParams.Kd_color.enable').setValue(1, 0) materialNode.getParameter('shaders.prmanSurfaceParams.Kd_color.value.i0').setValue(2.0, 0) materialNode.getParameter('shaders.prmanSurfaceParams.Kd_color.value.i1').setValue(0.3, 0) materialNode.getParameter('shaders.prmanSurfaceParams.Kd_color.value.i2').setValue(0.5, 0) materialNode.checkDynamicParameters() materialNode.getInputPort('in').connect(ponyCreateNode.getOutputPort('out')) lightCreateNode = NodegraphAPI.CreateNode('LightCreate', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(lightCreateNode, (500, 500)) lightCreateNode.getParameter('name').setValue('/root/world/lgt/light1', 0) lightCreateNode.getParameter('transform.translate.x').setValue(23, 0) lightCreateNode.getParameter('transform.translate.y').setValue(21, 0) lightCreateNode.getParameter('transform.translate.z').setValue(-6, 0) lightCreateNode.getParameter('transform.rotate.x').setValue(157, 0) lightCreateNode.getParameter('transform.rotate.y').setValue(74, 0) lightCreateNode.getParameter('transform.rotate.z').setValue(180, 0) lightMaterialNode = NodegraphAPI.CreateNode('Material', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(lightMaterialNode, (500, 400)) lightMaterialNode.getParameter('name').setValue('spotLight_shader', 0) lightMaterialNode.getParameter('namespace').setValue('lgt', 0) lightMaterialNode.addShaderType('prmanLight') lightMaterialNode.checkDynamicParameters() lightMaterialNode.getParameter('shaders.prmanLightShader.enable').setValue(1, 0) lightMaterialNode.getParameter('shaders.prmanLightShader.value').setValue('KatanaSpotlight', 0) lightMaterialNode.checkDynamicParameters() lightMaterialNode.getInputPort('in').connect(lightCreateNode.getOutputPort('out')) mergeNode = NodegraphAPI.CreateNode('Merge', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(mergeNode, (300,300)) mergeNode.addInputPort('i0').connect(cameraCreateNode.getOutputPort('out')) mergeNode.addInputPort('i1').connect(materialNode.getOutputPort('out')) mergeNode.addInputPort('i2').connect(lightMaterialNode.getOutputPort('out')) materialAssignNode = NodegraphAPI.CreateNode('MaterialAssign', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(materialAssignNode, (300,200)) materialAssignNode.getInputPort('input').connect(mergeNode.getOutputPort('out')) materialAssignNode.getParameter('CEL').setValue('/root/world/geo/pony', 0) materialAssignNode.getParameter('args.materialAssign.enable').setValue(1, 0) materialAssignNode.getParameter('args.materialAssign.value').setValue('/root/materials/geo/pink_mat', 0) lightMaterialAssignNode = NodegraphAPI.CreateNode('MaterialAssign', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(lightMaterialAssignNode, (300,100)) lightMaterialAssignNode.getInputPort('input').connect(materialAssignNode.getOutputPort('out')) lightMaterialAssignNode.getParameter('CEL').setValue('/root/world/lgt/light1', 0) lightMaterialAssignNode.getParameter('args.materialAssign.enable').setValue(1, 0) lightMaterialAssignNode.getParameter('args.materialAssign.value').setValue('/root/materials/lgt/spotLight_shader', 0) KatanaFile.Save('/tmp/pink_pony.katana') print "finished creating scene /tmp/pink_pony.katana" Create Prune node and set CEL parameter .. code-block:: python from Katana import NodegraphAPI # list of geometry that we want to prune pruneList = [ '/root/world/geo/mycmpt/mycmpt_body_grp/mycmpt_lf_shoe/mycmpt_lf_shoelace', '/root/world/geo/mycmpt/mycmpt_head_grp/mycmpt_cn_hat' ] # Create a Prune node myNode = NodegraphAPI.CreateNode('Prune', NodegraphAPI.GetRootNode()) # Get the CEL parameter (parameter is named 'cel') celParam = myNode.getParameter('cel') # Set the value celParam.setValue('(' + ' '.join(pruneList) + ')', 0) Create a series of lights, merge their outputs .. code-block:: python from Katana import NodegraphAPI # Take a list of nodes, and merge their outputs def MergeNodes(nodes, parent): merge = NodegraphAPI.CreateNode('Merge') merge.setParent(parent) for n in nodes: output = n.getOutputPortByIndex(0) if not output: continue numInputs = merge.getNumInputPorts() inputPort = merge.addInputPort('i%d' % numInputs) output.connect(inputPort) return merge # Create a few lightCreates allLightNodes = [] for lightName in ['key','fill','rim','bounce']: lightNode = NodegraphAPI.CreateNode('LightCreate', NodegraphAPI.GetRootNode()) lightNode.setName(lightName) scenegraphLocation = '/root/world/lgt/%s' % lightName lightNode.getParameter('name').setValue(scenegraphLocation, 0) allLightNodes.append(lightNode) # Merge the resulting nodes mergeNode = MergeNodes(allLightNodes, NodegraphAPI.GetRootNode()) # Set reasonable positions x,y = 0,0 for n in allLightNodes: NodegraphAPI.SetNodePosition(n,(x, y)) x+=100 NodegraphAPI.SetNodePosition(mergeNode,(x-250,y-200)) Find all Material nodes, set to an updated surfaceShader .. code-block:: python from Katana import NodegraphAPI oldSurfaceShader = "KatanaBlinn" newSurfaceShader = "KatanaPhong" for node in NodegraphAPI.GetAllNodes(): if node.getType() != "Material": continue #if node.getParameterValue("materialType", 0) != "geometry": # continue param = node.getParameter("shaders.prmanSurfaceShader.value") if param and param.getValue(NodegraphAPI.GetCurrentTime()) == oldSurfaceShader: param.setValue(newSurfaceShader, 0) name = node.getParameterValue("name", NodegraphAPI.GetCurrentTime()) print "Updated Material Shader:", name # Trigger node to rebuild shader parameters based on new shader name node.checkDynamicParameters() Creating an Arnold shading material network .. code-block:: python from Katana import NodegraphAPI imageNode = NodegraphAPI.CreateNode('ArnoldShadingNode', NodegraphAPI.GetRootNode()) imageNode.getParameter('name').setValue('image_node', 0) NodegraphAPI.SetNodePosition(imageNode, (-100, 100)) imageNode.getParameter('nodeType').setValue('image', 0) imageNode.checkDynamicParameters() imageNode.getParameter('parameters.filename').createChildString('hints', "{'widget': 'filename', 'dstPage': 'basics', 'dstName': 'image1'}") standardNode = NodegraphAPI.CreateNode('ArnoldShadingNode', NodegraphAPI.GetRootNode()) standardNode.getParameter('name').setValue('standard_node', 0) NodegraphAPI.SetNodePosition(standardNode, (0, 0)) standardNode.getParameter('nodeType').setValue('standard', 0) standardNode.checkDynamicParameters() standardNode.getParameter('parameters.Kd.enable').setValue(1, 0) standardNode.getParameter('parameters.Kd.value').setValue(0.8, 0) standardNode.getInputPort('Kd_color').connect(imageNode.getOutputPort('out')) networkMaterialNode = NodegraphAPI.CreateNode('NetworkMaterial', NodegraphAPI.GetRootNode()) NodegraphAPI.SetNodePosition(networkMaterialNode, (100, -100)) networkMaterialNode.addInputPort('arnoldSurface') networkMaterialNode.getInputPort('arnoldSurface').connect(standardNode.getOutputPort('out')) Attach selected nodes to mouse as "floating" in Nodegraph panel .. code-block:: python from Katana import NodegraphAPI from Katana import UI4 # Get list of selected nodes nodeList = NodegraphAPI.GetAllSelectedNodes() # Find Nodegraph tab and float nodes nodegraphTab = UI4.App.Tabs.FindTopTab('Node Graph') if nodegraphTab: nodegraphTab.floatNodes(nodeList) Create a Group node containing a network that produces a scene graph with sphere and cube locations .. code-block:: python # Constants TIME = 0 HALF_DISTANCE_APART = 1.0 # Create the group at root level rootNode = NodegraphAPI.GetRootNode() groupNode = NodegraphAPI.CreateNode('Group', rootNode) # Create the sphere at group level sphereNode = NodegraphAPI.CreateNode('PrimitiveCreate', groupNode) sphereNode.setName('Sphere') sphereNode.getParameter('name').setValue("/root/world/geo/sphere", TIME) sphereNode.getParameter('type').setValue('sphere', TIME) sphereNode.getParameter('transform.translate.x').setValue(HALF_DISTANCE_APART, TIME) NodegraphAPI.SetNodePosition(sphereNode, (-100, 100)) # Create the cube cubeNode = NodegraphAPI.CreateNode('PrimitiveCreate', groupNode) cubeNode.setName('Cube') cubeNode.getParameter('name').setValue("/root/world/geo/cube", TIME) cubeNode.getParameter('type').setValue('cube', TIME) cubeNode.getParameter('transform.translate.x').setValue(- HALF_DISTANCE_APART, TIME) NodegraphAPI.SetNodePosition(cubeNode, (100, 100)) # Create a Merge node at group level mergeNode = NodegraphAPI.CreateNode('Merge', groupNode) # Connect the two PrimitiveCreate nodes to a Merge node mergeSphereInPort = mergeNode.addInputPort('sphere') mergeCubeInPort = mergeNode.addInputPort('cube') mergeSphereInPort.connect(sphereNode.getOutputPort('out')) mergeCubeInPort.connect(cubeNode.getOutputPort('out')) # Rename our merge node to 'Result' to make it clear that this is the final result. mergeNode.setName('Result') RenderManager ------------- Start a Preview Render from a single selected node: .. code-block:: python from Katana import NodegraphAPI, RenderManager allSelectedNodes = NodegraphAPI.GetAllSelectedNodes() if len(allSelectedNodes) != 1: raise RuntimeError('Please select one node.') selectedNode = allSelectedNodes[0] RenderManager.StartRender(RenderManager.RenderModes.PREVIEW_RENDER, selectedNode)