Creating Your First Node

As we now understand how to work with the graph using existing nodes, this section of the tutorials walks through how to create new nodes to augment the existing functionality. OmniGraph uses a framework we call OGN (OmniGraph Nodes) for node creation. OGN is a powerful framework that takes a high level description of the node and generates most of the implementation required for the node. In this tutorial, it will be generating Python code, but it is capable of generating code in other languages like C++ as well. In addition, it’s capable of generating documentation and even tests for your node.

We’ll create two simple nodes, NegateDouble and AddDouble, to replace the functionality of the SubtractDouble node.

Please open the Node Description Editor:

../../_images/ext_omnigraph_deforming_text_03_01.png

First, we’ll create the NegateDouble node. Please fill in the first section of the Node Description Editor as seen below.

Caution

It is strongly recommended to leave the Extension Location field to its default value, as the application only looks for extensions in a fixed number of locations (for the precise list and instructions on how to alter it, please refer to general Omniverse docs). The default location above should be one of these locations. If you choose something else, make sure it’s a location where Omniverse is set to look for extensions, else your nodes will not load.

../../_images/ext_omnigraph_deforming_text_03_02.png

Next, please fill out the Inputs and Outputs sections as depicted blow:

../../_images/ext_omnigraph_deforming_text_03_03.png

Notice that as you’re filling out the information, the editor is showing you the raw .ogn file it is generating:

../../_images/ext_omnigraph_deforming_text_03_04.png

The .ogn file is what really matters here. It is a json file that describes what the node looks like from a high level. It is treated as a source file, which is parsed by our OGN framework, that then generates source files in Python (or C++), as well as documentation and tests. These generated source files provide functionality like accessing data, checking validity, and generally reduces boilerplate code to simplify the task for programmers to work with the system. The Node Description Editor UI you are using merely simplifies the task of writing the .ogn file, as new users may not be familiar with its syntax.

After filling out the information, click first on the “Populate Extension” button, followed by “Save Node”, followed by “Generate Blank Implementation”. The first button sets up the new extension. The second button generates the .ogn file within the extension. The third button generates a sample implementation file.

../../_images/ext_omnigraph_deforming_text_03_05.png

If all went well, you should already be able to place our new node into the system, even though at this time, with only the default implementation, it won’t do anything useful yet. Place a NegateDouble node into the graph and wire it up like so:

../../_images/ext_omnigraph_deforming_text_03_06.png

Let’s now navigate to the generated extension directory to take a look at the generated implementation file. If things were left at their default, this directory would be something like:

Documents/Kit/shared/exts/omni.new.extension/omni/new/extension/nodes

This is the source directory. Notice also the

Documents/Kit/shared/exts/omni.new.extension/omni/new/extension/ogn

directory. This is the generated code / documentation by the OGN framework. This is considered a build directory and not source, so do not check it in to your source code control system.

Open up the OgnNewNode.py file. It should look like the following:

"""
This is the implementation of the OGN node defined in OgnNewNode.ogn
"""

# Array or tuple values are accessed as numpy arrays so you probably need this import
import numpy

class OgnNewNode:
    """
    Takes a double as input and negates it
    """
    @staticmethod
    def compute(db) -> bool:
        """Compute the outputs from the current input"""

        try:
            # By putting the compute in a try block you can fail the compute by raising an exception
            pass
        except Exception as error:
            # If anything causes your compute to fail report the error and return False
            db.log_error(str(error))
            return False

        # Even if inputs were edge cases like empty arrays, correct outputs mean success
        return True

Note

Alternatively, we can also just click on the Edit Node button in the Node Description Editor to open up the implementation file OgnNewNode.py.

To complete our NegateDouble node, we only need to change a line or two:

"""
This is the implementation of the OGN node defined in OgnNewNode.ogn
"""

# Array or tuple values are accessed as numpy arrays so you probably need this import
import numpy

class OgnNewNode:
    """
    Takes a double as input and negates it
    """
    @staticmethod
    def compute(db) -> bool:
        """Compute the outputs from the current input"""

        try:
            # By putting the compute in a try block you can fail the compute by raising an exception
            input_value = db.inputs.in_double
            db.outputs.out_double = -1.0*input_value

        except Exception as error:
            # If anything causes your compute to fail report the error and return False
            db.log_error(str(error))
            return False

        # Even if inputs were edge cases like empty arrays, correct outputs mean success
        return True

Of course it is good form to remove the redundant and unnecessary information, which will also server to illustrate how lean a Python node implementation can be:

"""This is the implementation of the OGN node defined in OgnNewNode.ogn"""

class OgnNewNode:
    """Takes a double as input and negates it"""
    @staticmethod
    def compute(db) -> bool:
        db.outputs.out_double = - db.inputs.in_double
        return True

Once you save the file, notice that your node magically starts functioning:

../../_images/ext_omnigraph_deforming_text_03_07.png

This demonstrates the idea of “hot reloading”, which is very handy for Python nodes, and allows programmers to iterate rapidly.

Warning

In some versions of Kit there may be a problem when hot reloading a node with an existing instance in the scene. To work around this, select the nodes from the reloaded extension and use CTL-X/CTL-Z to delete the nodes and undo the delete, restoring them with the new functionality.

Now that our NegateDouble node is working, let’s move on to our next node, AddDouble. In the Node Description Editor, please click on File -> New Node to start the creation process for a new node:

../../_images/ext_omnigraph_deforming_text_03_08.png

Fill in the node details as follows:

../../_images/ext_omnigraph_deforming_text_03_09.png ../../_images/ext_omnigraph_deforming_text_03_10.png ../../_images/ext_omnigraph_deforming_text_03_11.png

Since the extension has already been populated, we do not need to click “Populate Extension” this time. Instead, click “Save Node” to save the ogn file as “OgnAddDouble.ogn” in the default directory, and then click “Generate Blank Implementation”:

../../_images/ext_omnigraph_deforming_text_03_12.png

Click on “Edit Node” to open the implementation file, and alter the implementation of the AddDouble node as follows:

"""
This is the implementation of the OGN node defined in OgnAddDouble.ogn
"""

class OgnAddDouble:
    """
    Add two doubles
    """
    @staticmethod
    def compute(db) -> bool:
        """Compute the outputs from the current input"""
        db.outputs.sum = db.inputs.input_a + db.inputs.input_b
        return True

Place the AddDouble node into the graph, wire it up and set its input value like so:

../../_images/ext_omnigraph_deforming_text_03_13.png

Go ahead and disconnect the SubtractDouble node from the ClampDouble node, by right clicking on the connection:

../../_images/ext_omnigraph_deforming_text_03_14.png

Wire the AddDouble node to the ClampDouble node as follows:

../../_images/ext_omnigraph_deforming_text_03_15.png

That’s it - as you move the sphere around, the graph should function as before. As a cleanup, consider deleting the dangling SubtractDouble node.

Note that to successfully run these nodes in a future session, you need to now enable your new extension (omni.new.extension) by loading it from the extension manager like the others. You may want to enable auto-load on the extension for convenience.

In the next chapter, we’ll cover how to create a more complex node - a deformer.