Creating Your First Deformer Node¶
Now that we have gone through the exercise of creating some simple nodes, it’s time to create a more complex node. To this end a deformer would be a good example, as it’s a fairly common use case.
In the Node Description Editor, please click on File -> New Node to start the creation process for a new node:
Fill in the node details as follows:
Note that for the in_points attribute we’re tagging it with a tuple size of 3, and making it an array (it’s also of type float, as opposed to double, as that tends to be the default data for point arrays in the USD sample we have).
From here click on “Save Node” to save the ogn file as “OgnTestDeformer.ogn” in the default directory, and then click “Generate Blank Implementation” to generate a sample implementation file.
Click on “Edit Node” to open the OgnTestDeformer.py implementation file and fill in its contents like so:
""" This is the implementation of the OGN node defined in OgnTestDeformer.ogn """ # Array or tuple values are accessed as numpy arrays so you probably need this import import numpy class OgnTestDeformer: """ A sine wave deformer """ @staticmethod def compute(db) -> bool: """Compute the outputs from the current input""" try: multiplier = db.inputs.multiplier points = db.inputs.in_points wavelength = 2 offset = 3.14 db.outputs.out_points_size = points.shape # Nothing to evaluate if there are no input points if db.outputs.out_points_size == 0: return True pt = points.copy() # we still need to do a copy here because we do not want to modify points tx = pt[:, 0] offset_tx = tx + offset ty = pt[:, 2] disp = (numpy.sin(offset_tx/wavelength) ) pt[:, 1] += disp * multiplier db.outputs.out_points[:] = pt[:] # we modify output_points in memory so we do not need to set the value again 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
Notice that arrays are bound to numpy - this allows us to have our internal buffers bound to Python without having to copy it, and also allows us to use numpy syntax and functionality for manipulating these arrays.
Now that the node is ready, let’s wire it up in the graph. Start with creating two nodes. Drag and drop PolyMeshPlane_in into the editor, and select “Read Attribute” to create a ReadPrimAttribute node. Set its Attribute Name to points. Drag and drop PolyMeshPlane_out into the editor, and select “Write Attribute” to create a WritePrimAttribute node. Also set its Attribute Name to points.
Proceed to place one of our TestDeformer nodes and wire it up like so:
Now, as you move the sphere around, the plane should deform, like so:
Finally, a note about the red “Clean Extension” button in the Node Description Editor that you may have noticed. As the ogn directory is a generated directory, it’s something akin to a build directory. It’s possible that as you add and remove nodes, extra stuff might accumulate in there, depending on your workflow. The button will scan the nodes directory and make sure what generated in the ogn directory matches up with it. You might try to use this button to do a “reset” if things are not working as you expect - first make sure the stuff in the nodes directory is good and up to date, then click this button to “reset” and clean things up.