Action Code Samples - C++

This file contains a collection of examples for implementing OGN nodes that work in Action Graphs. The features that are particular to Action Graph are accessed in C++ through the IActionGraph interface. All the concepts of OmniGraph apply equally to Action Graph nodes. See OGN User Guide.

Note

The API used in these samples are usable in kit-sdk version 105.1 or greater.

Password Branch Node

This example demonstrates branching the incoming control flow based on input data. The node activates the opened output if the password is correct.

#include <omni/graph/action/IActionGraph.h>

#include <OgnPasswordDatabase.h>

class OgnPassword
{
public:
    static bool compute(OgnPasswordDatabase& db)
    {
        auto iActionGraph = omni::graph::action::getInterface();
        auto password = db.inputs.password();

        // enable the output execution if authorized
        if (password == "Mellon")
            iActionGraph->setExecutionEnabled(outputs::opened.token(), kAccordingToContextIndex);
        else
            iActionGraph->setExecutionEnabled(outputs::denied.token(), kAccordingToContextIndex);

        return true;
    }
};
REGISTER_OGN_NODE()

[Python Version]

OnSelect Node

This example demonstrates an event node that activates the selected output when the kit selection changes. The implementation has to consider instances of nodes vs authored nodes because there are potentially many instances of a given node computing concurrently. Each authored node has a subscription to the UsdContext event stream, in addition there is one Stamp in the authored node state, which is synchronized with many SyncStamp in the node instance states.

// clang-format off
#include "UsdPCH.h"
// clang-format on

#include <omni/graph/action/IActionGraph.h>
#include <omni/kit/IApp.h>
#include <omni/usd/UsdContext.h>

#include <OgnOnSelectDatabase.h>

class OgnOnSelect
{
public:
    carb::ObjectPtr<carb::events::ISubscription> m_sub; // The stage event subscription handle
    omni::graph::exec::unstable::Stamp m_selectionChangedStamp; // The stamp set by the authoring node when the event
                                                                // occurs
    omni::graph::exec::unstable::SyncStamp m_selectionChangedSyncStamp; // The stamp used by each instance to sync with
                                                                        // above

    static void initialize(const GraphContextObj& context, const NodeObj& nodeObj)
    {
        auto& authoringState = OgnOnSelectDatabase::sInternalState<OgnOnSelect>(nodeObj, kAuthoringGraphIndex);
        authoringState.m_sub = carb::events::createSubscriptionToPop(
            omni::usd::UsdContext::getContext()->getStageEventStream().get(),
            [nodeHandle = nodeObj.nodeHandle](carb::events::IEvent* e)
            {
                if (static_cast<omni::usd::StageEventType>(e->type) == omni::usd::StageEventType::eSelectionChanged)
                {
                    auto iNode = carb::getCachedInterface<omni::graph::core::INode>();
                    NodeObj nodeObj = iNode->getNodeFromHandle(nodeHandle);
                    if (nodeObj.isValid())
                    {
                        auto& authoringState =
                            OgnOnSelectDatabase::sInternalState<OgnOnSelect>(nodeObj, kAuthoringGraphIndex);
                        authoringState.m_selectionChangedStamp.next();
                    }
                }
            });
    }

    static bool compute(OgnOnSelectDatabase& db)
    {
        auto const& authoringState =
            OgnOnSelectDatabase::sInternalState<OgnOnSelect>(db.abi_node(), kAuthoringGraphIndex);
        auto& localState = db.internalState<OgnOnSelect>();

        if (localState.m_selectionChangedSyncStamp.makeSync(authoringState.m_selectionChangedStamp))
        {
            auto iActionGraph = omni::graph::action::getInterface();
            iActionGraph->setExecutionEnabled(outputs::selected.token(), kAccordingToContextIndex);
        }
        return true;
    }
};
REGISTER_OGN_NODE()

[Python Version]

While Node

This example demonstrates activating an output several times in one update. The node activates the loopBody output while the condition is true, and finally calling the finished output.

#include <omni/graph/action/IActionGraph.h>

#include <OgnWhileDatabase.h>

class OgnWhile
{
public:
    static bool compute(OgnWhileDatabase& db)
    {
        auto iActionGraph = omni::graph::action::getInterface();
        auto keepGoing = db.inputs.keepGoing();

        // enable the output execution if authorized
        if (keepGoing)
            iActionGraph->setExecutionEnabledAndPushed(outputs::loopBody.token(), kAccordingToContextIndex);
        else
            iActionGraph->setExecutionEnabled(outputs::finished.token(), kAccordingToContextIndex);

        return true;
    }
};
REGISTER_OGN_NODE()

[Python Version]

DoN Node

This example demonstrates a node that enters a latent state for N ticks, before triggering the finished output. While counting down the evaluation will be “paused”, but continue to activate a ‘tick’ output. The node logic is if state:count is at the initial value (0), then start the latent state. If the count has reached n, end the latent state and trigger the output.

This is done with omni::graph::action::IActionGraph::startLatentState() and omni::graph::action::IActionGraph::endLatentState().

#include <omni/graph/action/IActionGraph.h>

#include <OgnDoNDatabase.h>

class OgnDoN
{
public:
    static bool compute(OgnDoNDatabase& db)
    {
        auto iActionGraph = omni::graph::action::getInterface();
        auto count = db.state.count();
        auto n = db.inputs.n();

        if (count == 0)
        {
            iActionGraph->startLatentState(kAccordingToContextIndex);
            db.state.count() += 1;
        }
        else if (count >= n)
        {
            db.state.count() = 0;
            iActionGraph->endLatentState(kAccordingToContextIndex);
            iActionGraph->setExecutionEnabled(outputs::finished.token(), kAccordingToContextIndex);
        }
        else
        {
            db.state.count() += 1;
            iActionGraph->setExecutionEnabled(outputs::tick.token(), kAccordingToContextIndex);
        }

        return true;
    }
};
REGISTER_OGN_NODE()

[Python Version]