OpScript Tutorials
Please note that the following examples are located in the Help > Example Projects menu in Katana, or within the katana install directory at $KATANA_HOME/demos/katana_files/opscript_tutorial.katana.
Creating Scene Graph Locations
Using CreateChild()
This example shows you how to create child locations using the OpScript node. By default, if you specify Interface.CreateChild(‘childName’) inside your OpScript without specifying the opType parameter, your child location inherits the opType used by the parent. So, in this case, it recursively uses this opType, OpScriptLua, and creates an infinite number of child locations.
Note: Please refer to OpScript for more information on any of the following functions, or for information on exposed functions for the OpScript.
There are a few solutions to this: check if we match the CEL, create a hierarchy based on an if-else statement, or use a StaticSceneCreate op to create a hierarchy.
Check If We Match the CEL
A simple way to get around this is to use the following command:
if Interface.AtRoot() then Interface.CreateChild("child_a") end
In the OpScript node, set the CEL statement to /root/world by previously creating a /root/world location using LocationCreate. Also make sure that the applyWhere parameter is set to at locations matching CEL.
Create a Hierarchy Based on if-else Statement
We create a hierarchy by checking which location we are currently at and executing the commands associated to that if statement. When this script is run for the first time, it creates a child location at /root, which is /root/world. Then, when the OpScript is executed at the child location, it creates /root/world/geo. This continues until the last condition is met. In this way, we avoid infinite recursion. We’ve set the applyWhere parameter to at all locations too, so that we don’t need to worry about specifying /root.
Use a StaticSceneCreate Op to Create a Hierarchy
We can use the StaticSceneCreate op to create a hierarchy without the use of if-else statements using the OpArgsBuilder.StaticSceneCreate() function. You can input the following directly into an OpScript node, or refer to the example OpScript Tutorial file. Again, we’ve set the applyWhere parameter to be run at all locations.
Deleting Scene Graph Locations
There are three methods available to remove scene graph locations: deleteChild(), deleteChildren() and deleteSelf(). By allowing you to remove your own scene graph locations, you can re-implement your own Prune node, for instance. This tutorial looks at each of these methods, but please refer to the OpScript Tutorial Example Projects for context. You can comment or uncomment the relevant commands.
Delete the Child by Name
The OpScript node allows you to delete newly-created children and incoming child locations, like so:
Interface.DeleteChild("child_a")
Note that child_a is the immediate child of the matching CEL. For example, if your CEL statement looked like this:
/root/world/geo/parent
and the children that exist here are
/root/world/geo/parent/child_a and /root/world/geo/parent/child_a/grandchild_a
the DeleteChild() function cannot delete grandchild_a.
Delete All Children
Deleting all children under which the OpScript is being cooked at is straightforward. This also deletes all newly-created children and incoming ones:
Interface.DeleteChildren()
Delete Self
You are also able to delete the current output location using Interface.DeleteSelf(), however, all calls to DeleteSelf() keep the location in its parent’s potential children list. So, it’s advisable to use DeleteChild() instead, if possible.
Copying Scene Graph Locations and Attributes
Since the attributes are being copied over along with the scene graph locations, we can use this to our advantage. As the OpScript node supports multiple inputs, you can effectively recreate a custom Merge or Switch node, again, increasing the potential of the OpScript node.
Using the same function as above, look at how you can copy from one input to another. Please refer to the OpScript Tutorials example file for context.
We have two LocationCreate nodes and an AttributeSet node corresponding to each LocationCreate node. The two node graph branches are then connected to separate input ports of the OpScript node. The CopyLocationToChild() function that we used in the previous example has two extra arguments that we haven’t explicitly specified; they are: the input index and the order of where you want to place your new hierarchy.
if Interface.AtRoot() then Interface.CopyLocationToChild("target_child_a","/root/world/another_parent/another_child_a", 1, "child_a") -- Interface.CopyLocationToChild("target_child_a","/root/world/parent/child_a", 0, "child_a") end
This script copies over the name attribute from the second input of the OpScript to the target_child_a location. The name changes depending on which line you comment/uncomment.
Creating Scene Graph Locations
Using CreateChild()
This example shows you how to create child locations using the OpScript node. By default, if you specify Interface.CreateChild(‘childName’) inside your OpScript without specifying the opType parameter, your child location inherits the opType used by the parent. So, in this case, it recursively uses this opType, OpScriptLua, and creates an infinite number of child locations.
Note: Please refer to OpScript for more information on any of the following functions, or for information on exposed functions for the OpScript.
There are a few solutions to this: check if we match the CEL, create a hierarchy based on an if-else statement, or use a StaticSceneCreate op to create a hierarchy.
Check If We Match the CEL
A simple way to get around this is to use the following command:
if Interface.AtRoot() then Interface.CreateChild("child_a") end
In the OpScript node, set the CEL statement to /root/world by previously creating a /root/world location using LocationCreate. Also make sure that the applyWhere parameter is set to at locations matching CEL.
Create a Hierarchy Based on if-else Statement
We create a hierarchy by checking which location we are currently at and executing the commands associated to that if statement. When this script is run for the first time, it creates a child location at /root, which is /root/world. Then, when the OpScript is executed at the child location, it creates /root/world/geo. This continues until the last condition is met. In this way, we avoid infinite recursion. We’ve set the applyWhere parameter to at all locations too, so that we don’t need to worry about specifying /root.
path = Interface.getOutputLocationPath() if path == "/root" then Interface.CreateChild("world") elseif path == "/root/world" then Interface.CreateChild("parent") elseif path == "/root/world/parent" then Interface.CreateChild("child_a") elseif path == "/root/world/parent/child_a" then Interface.SetAttr("test", IntAttribute(123)) end
Use a StaticSceneCreate Op to Create a Hierarchy
We can use the StaticSceneCreate op to create a hierarchy without the use of if-else statements using the OpArgsBuilder.StaticSceneCreate() function. You can input the following directly into an OpScript node, or refer to the example OpScript Tutorial file. Again, we’ve set the applyWhere parameter to be run at all locations.
sscb = OpArgsBuilders.StaticSceneCreate(true) sscb:createEmptyLocation("/root/world/parent/child_a", "group") --create a scenegraph location with a type sscb:setAttrAtLocation("/root/world/parent/child_a", "test_id", IntAttribute(123)) --set the attribute Interface.ExecOp("StaticSceneCreate", sscb:build()) --execute the Op
Deleting Scene Graph Locations
There are three methods available to remove scene graph locations: deleteChild(), deleteChildren() and deleteSelf(). By allowing you to remove your own scene graph locations, you can re-implement your own Prune node, for instance. This tutorial looks at each of these methods, but please refer to the OpScript Tutorial Example Projects for context. You can comment or uncomment the relevant commands.
Delete the Child by Name
The OpScript node allows you to delete newly-created children and incoming child locations, like so:
Interface.DeleteChild("child_a")
Note that child_a is the immediate child of the matching CEL. For example, if your CEL statement looked like this:
/root/world/geo/parent
and the children that exist here are
/root/world/geo/parent/child_a and /root/world/geo/parent/child_a/grandchild_a
the DeleteChild() function cannot delete grandchild_a.
Delete All Children
Deleting all children under which the OpScript is being cooked at is straightforward. This also deletes all newly-created children and incoming ones:
Interface.DeleteChildren()
Delete Self
You are also able to delete the current output location using Interface.DeleteSelf(), however, all calls to DeleteSelf() keep the location in its parent’s potential children list. So, it’s advisable to use DeleteChild() instead, if possible.
Copying Scene Graph Locations and Attributes
Another useful feature of the OpScript node is the ability to copy scene graph locations. For instance, allowing you to re-implement the HierarchyCopy node, if you wish. You can achieve this using Interface.CopyLocationToChild() function. Please refer to the OpScript Tutorial Example Projects and use the following code in conjunction for understanding the process.
Copying Scene Graph Hierarchies
These tutorials have shown how you can copy hierarchies very easily using the CopyLocationToChild() function. Using the following piece of Lua code, we can copy the /root/world/geo/parent_a hierarchy to the locations matching the CEL statement provided, in this case, /root/world/geo. The result is another hierarchy at /geo with /root/world/geo/parent_b/child_a. The resultant hierarchy has all the attributes copied over too.
if Interface.AtRoot() then Interface.CopyLocationToChild("parent_b", "/root/world/geo/parent_a") end
Copying Attributes Across Different Inputs
Since the attributes are being copied over along with the scene graph locations, we can use this to our advantage. As the OpScript node supports multiple inputs, you can effectively recreate a custom Merge or Switch node, again, increasing the potential of the OpScript node.
Using the same function as above, look at how you can copy from one input to another. Please refer to the OpScript Tutorials example file for context.
We have two LocationCreate nodes and an AttributeSet node corresponding to each LocationCreate node. The two node graph branches are then connected to separate input ports of the OpScript node. The CopyLocationToChild() function that we used in the previous example has two extra arguments that we haven’t explicitly specified; they are: the input index and the order of where you want to place your new hierarchy.
if Interface.AtRoot() then Interface.CopyLocationToChild("target_child_a","/root/world/another_parent/another_child_a", 1, "child_a") -- Interface.CopyLocationToChild("target_child_a","/root/world/parent/child_a", 0, "child_a") end
This script copies over the name attribute from the second input of the OpScript to the target_child_a location. The name changes depending on which line you comment/uncomment.