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. .. note:: These Python scripts described here are different to those used in the AttributeScript node. The scripts described here are for creating and editing node graphs. Attribute scripts are for inspecting and modifying scenegraph attributes when the Katana recipe is being evaluated. 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 ------------- Launch a new render of the specfied node .. code-block:: python from Katana import NodegraphAPI, RenderManager allSelectedNodes = NodegraphAPI.GetAllSelectedNodes() if len(allSelectedNodes)!=1: raise RuntimeError, 'Please select 1 node.' selectedNode = allSelectedNodes[0] RenderManager.StartRender(selectedNode)