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()
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()
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()
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()