Creating Your Own Graph

Now that we understand the basics of navigating and viewing an existing graph, the next step is naturally to create our own graphs with existing nodes. In this part of the tutorial we’ll hook up the graph for one of the letters, so that it changes color and moves up and down as we move our sphere around.

Please open the file deforming_text_tutorial_start.usda from the folder omni.graph.examples.python/data.

Create a new graph by clicking on Window -> Visual Scripting -> Generic Graph -> New Push Graph:

../../_images/ext_omnigraph_deforming_text_02_01.png

Note

You might be wondering what a push graph is. It’s a type of graph that evaluates every node in every frame. It is very simple to use, but at the same time it’s also fairly inefficient.

To start things off, we’ll need some data from the sphere, so we need its ReadPrimAttribute node in the graph. Drag and drop the sphere from the stage view onto the Graph Editor like so:

../../_images/ext_omnigraph_deforming_text_02_02.png

In the popup dialog, select Read Attribute. This creates a ReadPrimAttribute node from the sphere prim that we dragged in, and such a node allows us to read attributes from regular prims on the USD stage.

We also need to specify which attribute of the sphere prim do we want to read. Click on the new node. In the Property window on the right, set Attribute Name to xformOp:translate to read the position information of the sphere.

../../_images/ext_omnigraph_deforming_text_02_03.png

ReadPrimAttribute nodes act as the source of the data for our computations, and WritePrimAttribute nodes act as the destination (sink) of the data when the computation is finished. So the pattern you’ll often see is:

ReadPrimAttribute node -> compute node -> compute node -> … -> WritePrimAttribute node

In this case, the sphere’s ReadPrimAttribute node is going to act as the source of our computation. These Read/Write Attribute nodes are crucial to our system because without them, there’d be no source of data and nowhere to put the data once the computation has completed.

As an aside, another way to create such nodes is by searching for Read Prim Attribute on the left hand side, and then dragging it into the graph editor:

../../_images/ext_omnigraph_deforming_text_02_04.png

Once it is inside the graph editor, click Add Target -> Sphere -> Add to link it with the sphere prim. Finally set its Attribute Name to xformOp:translate as before.

../../_images/ext_omnigraph_deforming_text_02_05.png

Tip

Clicking on the icon with three dots at the top toolbar, or clicking twice on the similar icon on the node are the two ways to fully expand the node icon to show all available attributes.

Now that we have our first node in the graph, let’s move onto the second. On the left hand side, search for PositionToColor, and drag the node into the graph editor:

../../_images/ext_omnigraph_deforming_text_02_06.png

Note that in order to use nodes from a particular extension, the extension itself must first be loaded, otherwise the nodes will not show up in the left hand side.

Connect the Value attribute of ReadPrimAttribute to the Position attribute of PositionToColor by dragging from one port to the other.

Select the PositionToColor node to display the attributes in the property window. Set the inputs:scale attribute to 3. Notice the output:color is already being computed.

../../_images/ext_omnigraph_deforming_text_02_07.png

Note

You might notice that the node:type value in the Property tab is not exactly the same as the node type you selected when creating the node. This is because in order to ensure internal node type names are unique the name of the extension that created them is added as a prefix. Hence PositionToColor became omni.graph.examples.python.PositionToColor. It is up to the individual extension to ensure uniqueness within that extension.

Next, let’s create a WritePrimAttribute node to act as the sink of our computation.

Drag the Text_O mesh into the Graph Editor and select Write Attribute. Set its Attribute Name to primvars:displayColor. Connect the Color attribute of PositionToColor to the Value attribute of WritePrimAttribute:

../../_images/ext_omnigraph_deforming_text_02_08.png

Voila! We have a first working graph! If you now drag the sphere around, the “O” letter should change color:

../../_images/ext_omnigraph_deforming_text_02_09.png

Next, we can start hook up the other branch of the graph that drives the position of the letter. Add the DecomposeDouble3 node to decompose the position attribute into its constituent parts. Hook that up to an AbsDouble node to take the absolute value, and then a SubtractDouble node:

../../_images/ext_omnigraph_deforming_text_02_10.png

Select the SubtractDouble node and set its inputs:a attribute to 3, as the grid is about 3 units long in each direction.

Note

Technically the name of the DecomposeDouble3 node is DecomposeDouble3 (Python). Same goes for many other nodes mentioned in this tutorial.

Next, put down a ClampDouble node and set its inputs:max to 10:

../../_images/ext_omnigraph_deforming_text_02_11.png

We’ll want to control how high the text moves in response to the sphere moving, so create a MultDouble node, wire it up and set the inputs:a attribute to 0.18:

../../_images/ext_omnigraph_deforming_text_02_12.png

Create a ComposeDouble3 node, wire up the output of the MultDouble node to the inputs:z attribute as we want the letter to move up and down and our scene is z-up. Take care to set the inputs:x value to -2.34 though, as otherwise our letter will be stuck near the origin:

../../_images/ext_omnigraph_deforming_text_02_13.png

Finally, it’s time to bring all together. Drag the Text_O mesh into the graph editor to create a WritePrimAttribute node. Set its Attribute Name to xformOp:translate. Wire up the ComposeDouble3 node to the Value attribute:

../../_images/ext_omnigraph_deforming_text_02_14.png

That’s it! Now, as you move the sphere around, the letter should bounce up and down as well as changing color.

Next, we’ll look at how you can create your own nodes with its own behavior in Python.