Tutorial 12 - Python ABI Override Node¶
Although the .ogn format creates an easy-to-use interface to the ABI of the OmniGraph node and the associated data model, there may be cases where you want to override the ABI to perform special processing.
OgnTutorialABIPy.ogn¶
The ogn file shows the implementation of a node named “omni.graph.tutorials.AbiPy”, in its first version, with a simple description.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | { "AbiPy" : { "version": 1, "categories": ["tutorials", { "internal:abiPy": "Internal nodes that override the Python ABI functions" }], "language": "python", "description": ["This tutorial node shows how to override ABI methods on your Python node.", "The algorithm of the node converts an RGB color into HSV components."], "metadata": { "uiName": "Tutorial Python Node: ABI Overrides" }, "inputs": { "color": { "type": "colord[3]", "description": ["The color to be converted"], "default": [0.0, 0.0, 0.0], "metadata": { "$comment": "Metadata is key/value pairs associated with the attribute type.", "$specialNames": "Kit may recognize specific keys. 'uiName' is a human readable version of the attribute name", "uiName": "Color To Convert", "multipleValues": ["value1", "value2", "value3"] } } }, "outputs": { "h": { "type": "double", "description": ["The hue component of the input color"] }, "s": { "type": "double", "description": ["The saturation component of the input color"] }, "v": { "type": "double", "description": ["The value component of the input color"] } }, "tests": [ {"inputs:color": [0.2, 0.4, 0.4], "outputs:h": 0.5, "outputs:s": 0.5, "outputs:v": 0.4} ] } } |
OgnTutorialABIPy.py¶
The py file contains the implementation of the node class with every possible ABI method replaced with customized processing. The node still functions the same as any other node, although it is forced to write a lot of extra boilerplate code to do so.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | """ Implementation of the Python node accessing all of the simple data types. This class exercises access to the DataModel through the generated database class for all simple data types. It implements the same algorithm as the C++ node OgnTutorialABI.cpp """ import colorsys from contextlib import suppress import carb class OgnTutorialABIPy: """Illustrate overrides of the various ABI functions available to a Python OmniGraph node""" @staticmethod def compute(context_helper, node) -> bool: """ Convert a color into components using the raw ABI function without the nice Database interface. Rarely Overridden: Usually you will implement the much more friendly and Pythonic compute(OgnTutorialABIDatabasePy) method so that you can have easier access to your data. """ # Manually acquire the data on the known attributes input_color_attr = node.get_attribute("inputs:color") # Extract the input value from the helper input_color = context_helper.get_attr_value(input_color_attr) output_hue_attr = node.get_attribute("outputs:h") output_saturation_attr = node.get_attribute("outputs:s") output_value_attr = node.get_attribute("outputs:v") (h, s, v) = colorsys.rgb_to_hsv(*input_color) # This exception is triggered if you accidentally reverse the parameters to set_attr_value. # The error isn't recovered, to prevent proliferation of inconsistent calls. The exception is # thrown to help with debugging. (As this is an example the exception is caught and ignored here.) with suppress(TypeError): context_helper.set_attr_value(output_hue_attr, h) context_helper.set_attr_value(h, output_hue_attr) context_helper.set_attr_value(s, output_saturation_attr) context_helper.set_attr_value(v, output_value_attr) # # For comparison, here is the same algorithm implemented using "compute(db)" # # def compute(db) -> bool: # (db.outputs.h, db.outputs.s, db.outputs.v) = colorsys.rgb_to_hsv(*db.inputs.color) return True # ---------------------------------------------------------------------- @staticmethod def get_node_type() -> str: """ Rarely overridden This should almost never be overridden as the auto-generated code will handle the name """ carb.log_info("Python ABI override of get_node_type") return "omni.graph.tutorials.AbiPy" # ---------------------------------------------------------------------- @staticmethod def initialize(graph_context, node): """ Occasionally overridden This method might be overridden to set up initial conditions when a node of this type is created. Note that overridding this puts the onus on the node writer to set up initial conditions such as attribute default values and metadata. When a node is created this will be called """ carb.log_info("Python ABI override of initialize") # There is no default behaviour on initialize so nothing else is needed for this tutorial to function # ---------------------------------------------------------------------- @staticmethod def initialize_type(node_type) -> bool: """ Rarely overridden This method might be overridden to set up initial conditions when a node type is registered. Note that overriding this puts the onus on the node writer to initialize the attributes and metadata. By returning "True" the function is requesting that the attributes and metadata be initialized upon return, otherwise the caller will assume that this override has already done that. """ carb.log_info("Python ABI override of initialize_type") return True # ---------------------------------------------------------------------- @staticmethod def release(node): """ Occasionally overridden After a node is removed it will get a release call where anything set up in initialize() can be torn down """ carb.log_info("Python ABI override of release") # There is no default behaviour on release so nothing else is needed for this tutorial to function # ---------------------------------------------------------------------- @staticmethod def update_node_version(graph_context, node, old_version: int, new_version: int): """ Occasionally overridden This is something you do want to override when you have more than version of your node. In it you would translate attribute information from older versions into the current one. """ carb.log_info(f"Python ABI override of update_node_version from {old_version} to {new_version}") # There is no default behaviour on update_node_version so nothing else is needed for this tutorial to function return old_version < new_version # ---------------------------------------------------------------------- @staticmethod def on_connection_type_resolve(node): """ Occasionally overridden When there is a connection change to this node which results in an extended type attribute being automatically resolved, this callback gives the node a change to resolve other extended type attributes. For example a generic 'Increment' node can resolve its output to an int only after its input has been resolved to an int. Attribute types are resolved using omni.graph.attribute.set_resolved_type(), or the utility functions such as og.resolve_fully_coupled(). """ carb.log_info("Python ABI override of on_connection_type_resolve") # There is no default behaviour for on_connection_type_resolve so nothing else is needed for this # tutorial to function |
Metadata Attached To Attributes¶
This file introduces the metadata keyword to attributes, whose value is a dictionary of key/value pairs associated with the attribute in which it appears that may be extracted using the ABI metadata functions. These are not persisted in any files and so must be set either in the .ogn file or in an override of the initialize() method in the node definition.