Tutorial 21 - Adding Bundled Attributes¶
Sometimes instead of simply copying data from an input or input bundle into an output bundle you might want to construct a bundle from some other criteria. For example a bundle construction node could take in an array of names and attribute types and output a bundle consisting of those attributes with some default values.
The bundle accessor provides a simple method that can accomplish this task. Adding a new attribute is as simple as providing those two values to the bundle for every attribute you wish to add.
There is also a complementary function to remove named bundle attributes.
OgnTutorialBundleAddAttributes.ogn¶
The ogn file shows the implementation of a node named “omni.graph.tutorials.BundleData”, which has one input bundle and one output bundle.
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 | { "BundleAddAttributes": { "description": [ "This is a tutorial node. It exercises functionality for adding and removing attributes on", "output bundles." ], "version": 1, "categories": "tutorials", "uiName": "Tutorial Node: Bundle Add Attributes", "inputs": { "typesToAdd": { "type": "token[]", "description": [ "List of type descriptions to add to the bundle. The strings in this list correspond to the", "strings that represent the attribute types in the .ogn file (e.g. float[3][], colord[3], bool" ], "uiName": "Attribute Types To Add" }, "addedAttributeNames": { "type": "token[]", "description": [ "Names for the attribute types to be added. The size of this array must match the size", "of the 'typesToAdd' array to be legal." ] }, "removedAttributeNames": { "type": "token[]", "description": "Names for the attribute types to be removed. Non-existent attributes will be ignored." }, "useBatchedAPI": { "type": "bool", "description": "Controls whether or not to used batched APIS for adding/removing attributes" } }, "outputs": { "bundle": { "type": "bundle", "description": ["This is the bundle with all attributes added by compute."], "uiName": "Constructed Bundle" } } } } |
OgnTutorialBundleAddAttributes.cpp¶
The cpp file contains the implementation of the compute method. It accesses the attribute descriptions on the inputs and creates a bundle with attributes matching those descriptions as its output.
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 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. // // NVIDIA CORPORATION and its licensors retain all intellectual property // and proprietary rights in and to this software, related documentation // and any modifications thereto. Any use, reproduction, disclosure or // distribution of this software and related documentation without an express // license agreement from NVIDIA CORPORATION is strictly prohibited. // #include <OgnTutorialBundleAddAttributesDatabase.h> #include <omni/graph/core/IAttributeType.h> using omni::graph::core::Type; class OgnTutorialBundleAddAttributes { public: static bool compute(OgnTutorialBundleAddAttributesDatabase& db) { const auto& attributeTypeNames = db.inputs.typesToAdd(); const auto& attributeNames = db.inputs.addedAttributeNames(); const auto& useBatchedAPI = db.inputs.useBatchedAPI(); auto& outputBundle = db.outputs.bundle(); // The usual error checking. Being diligent about checking the data ensures you will have an easier time // debugging the graph if anything goes wrong. if (attributeTypeNames.size() != attributeNames.size()) { db.logWarning( "Number of attribute types (%zu) does not match number of attribute names (%zu)", attributeTypeNames.size(), attributeNames.size() ); return false; } // Make sure the bundle is starting from empty outputBundle.clear(); if (useBatchedAPI) { // // unfortunately we need to build a vector of the types // auto typeNameIt = std::begin(attributeTypeNames); std::vector<Type> types; types.reserve(attributeTypeNames.size()); for (; typeNameIt != std::end(attributeTypeNames); ++typeNameIt) { auto typeName = *typeNameIt; types.emplace_back(db.typeFromName(typeName)); } outputBundle.addAttributes(attributeTypeNames.size(), attributeNames.data(), types.data()); // Remove attributes from the bundle that were already added. This is a somewhat contrived operation that // allows testing of both adding and removal within a simple environment. if (db.inputs.removedAttributeNames().size()) { outputBundle.removeAttributes(db.inputs.removedAttributeNames().size(), db.inputs.removedAttributeNames().data()); } } else { // Since the two arrays are the same size a dual loop can be used to walk them in pairs auto typeNameIt = std::begin(attributeTypeNames); auto attributeNameIt = std::begin(attributeNames); for (; typeNameIt != std::end(attributeTypeNames) && attributeNameIt != std::end(attributeNames); ++typeNameIt, ++attributeNameIt) { auto typeName = *typeNameIt; auto attributeName = *attributeNameIt; auto typeNameString = db.tokenToString(typeName); Type newType = db.typeFromName(typeName); // Ignore the output since for this example there will not be any values set on the new attribute (void)outputBundle.addAttribute(attributeName, newType); } // Remove attributes from the bundle that were already added. This is a somewhat contrived operation that // allows testing of both adding and removal within a simple environment. for (const auto& toRemove : db.inputs.removedAttributeNames()) { outputBundle.removeAttribute(toRemove); } } return true; } }; REGISTER_OGN_NODE() |
OgnTutorialBundleAddAttributesPy.py¶
The py file contains the same algorithm as the C++ node, with only the implementation language being different.
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 | """ Implementation of the Python node adding attributes with a given description to an output bundle. """ import omni.graph.core as og class OgnTutorialBundleAddAttributesPy: """Exercise the bundled data types through a Python OmniGraph node""" @staticmethod def compute(db) -> bool: """Implements the same algorithm as the C++ node OgnTutorialBundleAddAttributes.cpp using the Python bindings to the bundle method """ # Start with an empty output bundle. output_bundle = db.outputs.bundle output_bundle.clear() if db.inputs.useBatchedAPI: attr_types = [og.AttributeType.type_from_ogn_type_name(type_name) for type_name in db.inputs.typesToAdd] output_bundle.add_attributes(attr_types, db.inputs.addedAttributeNames) output_bundle.remove_attributes(db.inputs.removedAttributeNames) else: for attribute_type_name, attribute_name in zip(db.inputs.typesToAdd, db.inputs.addedAttributeNames): attribute_type = og.AttributeType.type_from_ogn_type_name(attribute_type_name) output_bundle.insert((attribute_type, attribute_name)) # Remove attributes from the bundle that were already added. This is a somewhat contrived operation that # allows testing of both adding and removal within a simple environment. for attribute_name in db.inputs.removedAttributeNames: output_bundle.remove(attribute_name) return True |