Houdini Engine 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Nodes

Nodes Basics

All functions and data in Houdini is represented as nodes. Nodes are exposed via a HAPI_NodeId which can be used to get and set parameter information and values from that node.

In Houdini Engine, nodes are identified via a HAPI_NodeId. These ids are given by various functions and structs throughout the API. For example, HAPI_AssetInfo's, HAPI_ObjectInfo's, HAPI_GeoInfo's, and HAPI_MaterialInfo's all have HAPI_NodeId's that pertain to the underlying Houdini nodes they represent. Note that HAPI_PartInfo does NOT have a HAPI_NodeId, as it is pure a construct in HAPI and does not map directly to an underlying Houdini node.

One of the main uses of nodes in HAPI is for storing parameter information needed to get and set parameter values. See Parameters.

Given a HAPI_NodeId you can fill a HAPI_NodeInfo struct with a call to HAPI_GetNodeInfo().

Editable Node Networks

You can promote a node network (any node in Houdini that can have nodes inside it) as an editable node network by adding its relative path to the Editable Nodes field of your asset's Operator Type Properties, under the Node tab.

You can then query the list of editable node networks using HAPI_GetEditableNodeNetworks().

Create, Delete, Connect Nodes

Once you have the HAPI_NodeId of a node you know is a node network, like one returned from HAPI_GetEditableNodeNetworks(), you can start creating, deleting, and connecting nodes inside it.

First, you will probably want to see what is already inside a node network with HAPI_GetNodeNetworkChildren(). The number of children in a node network is given by HAPI_NodeInfo::childNodeCount.

After creating or deleting nodes, don't forget to re-fetch the HAPI_NodeInfo of the node network using HAPI_GetNodeInfo() to get the updated HAPI_NodeInfo::childNodeCount.

Create Node

You can create nodes with HAPI_CreateNode(). The operator_name parameter should include only the namespace, name, and version, For example, if you have an Object type asset, in the "hapi" namespace, of version 2.0, named "foo", the operator_name here will be: "hapi::foo::2.0". Normally, if you don't have a namespace or version, just pass "foo".

Here's an example of creating a Box SOP node in an exposed OBJ node network:

// Load the library from file.
HAPI_AssetLibraryId library_id = -1;
hapiTestSession, "HAPI_Test_Nodes_EditableNodeNetwork.otl",
false, &library_id );
assert( result == HAPI_RESULT_SUCCESS );
assert( library_id >= 0 );
// Instantiate the asset.
HAPI_AssetId asset_id = -1;
hapiTestSession, "Object/HAPI_Test_Nodes_EditableNodeNetwork", true,
&asset_id );
assert( result == HAPI_RESULT_SUCCESS );
// Get and verify the asset info.
HAPI_AssetInfo asset_info;
result = HAPI_GetAssetInfo( hapiTestSession, asset_id, &asset_info );
assert( result == HAPI_RESULT_SUCCESS );
HAPI_NodeId network_node_id;
hapiTestSession,
asset_id, &network_node_id,
assert( result == HAPI_RESULT_SUCCESS );
HAPI_NodeInfo network_node_info;
result = HAPI_GetNodeInfo(
hapiTestSession, network_node_id, &network_node_info );
assert( result == HAPI_RESULT_SUCCESS );
assert( network_node_info.childNodeCount == 2 );
// Create a node.
HAPI_NodeId box_node_id;
result = HAPI_CreateNode(
hapiTestSession, network_node_id, "box", &box_node_id );
assert( result == HAPI_RESULT_SUCCESS );
// Check new child count.
result = HAPI_GetNodeInfo(
hapiTestSession, network_node_id, &network_node_info );
assert( result == HAPI_RESULT_SUCCESS );
assert( network_node_info.childNodeCount == 3 );
// Get and verify the box node info.
HAPI_NodeInfo box_node_info;
result = HAPI_GetNodeInfo( hapiTestSession, box_node_id, &box_node_info );
assert( result == HAPI_RESULT_SUCCESS );
assert( box_node_info.createdPostAssetLoad == true );

Delete Node

You can delete nodes with HAPI_DeleteNode(). Note that you can only delete nodes that you created with HAPI_CreateNode() or that were created via an internal script in the asset (like Python). More specifically, you can only delete nodes that have their HAPI_NodeInfo::createdPostAssetLoad set to true.

Here's an example of deleting nodes:

// Load the library from file.
HAPI_AssetLibraryId library_id = -1;
hapiTestSession, "HAPI_Test_Nodes_EditableNodeNetwork.otl",
false, &library_id );
assert( result == HAPI_RESULT_SUCCESS );
assert( library_id >= 0 );
// Instantiate the asset.
HAPI_AssetId asset_id = -1;
hapiTestSession, "Object/HAPI_Test_Nodes_EditableNodeNetwork",
true, &asset_id );
assert( result == HAPI_RESULT_SUCCESS );
// Get and verify the asset info.
HAPI_AssetInfo asset_info;
result = HAPI_GetAssetInfo( hapiTestSession, asset_id, &asset_info );
assert( result == HAPI_RESULT_SUCCESS );
HAPI_NodeId network_node_id;
hapiTestSession,
asset_id, &network_node_id,
assert( result == HAPI_RESULT_SUCCESS );
HAPI_NodeInfo network_node_info;
result = HAPI_GetNodeInfo(
hapiTestSession, network_node_id, &network_node_info );
assert( result == HAPI_RESULT_SUCCESS );
assert( network_node_info.childNodeCount == 2 );
// Create a node.
HAPI_NodeId box_node_id;
result = HAPI_CreateNode(
hapiTestSession, network_node_id, "box", &box_node_id );
assert( result == HAPI_RESULT_SUCCESS );
// Delete the node.
result = HAPI_DeleteNode( hapiTestSession, box_node_id );
assert( result == HAPI_RESULT_SUCCESS );
// Check new child count.
result = HAPI_GetNodeInfo(
hapiTestSession, network_node_id, &network_node_info );
assert( result == HAPI_RESULT_SUCCESS );
assert( network_node_info.childNodeCount == 2 );
// Make sure asset is still valid!
result = HAPI_GetAssetInfo( hapiTestSession, asset_id, &asset_info );
assert( result == HAPI_RESULT_SUCCESS );
// Try to delete a node that was part of the original asset.
result = HAPI_DeleteNode( hapiTestSession, network_node_id );
assert( result == HAPI_RESULT_INVALID_ARGUMENT );

Connecting Nodes

You can also connect nodes with HAPI_ConnectNodeInput(), disconnect them with HAPI_DisconnectNodeInput(), and query existing connections with HAPI_QueryNodeInput(). HAPI_QueryNodeInput() will return -1 as the node id of the connected node if nothing is connected.

If any of these node changes have an affect on an HAPI-exposed part of the asset, like the Material or Geo, you need to call HAPI_CookAsset() for the changes to be incorporated.

Here's an example of connecting two nodes and then disconnecting them - querying the connection at each step:

// Load the library from file.
HAPI_AssetLibraryId library_id = -1;
hapiTestSession, "HAPI_Test_Nodes_EditableNodeNetwork.otl",
false, &library_id );
assert( result == HAPI_RESULT_SUCCESS );
assert( library_id >= 0 );
// Instantiate the asset.
HAPI_AssetId asset_id = -1;
hapiTestSession, "Object/HAPI_Test_Nodes_EditableNodeNetwork",
true, &asset_id );
assert( result == HAPI_RESULT_SUCCESS );
// Get and verify the asset info.
HAPI_AssetInfo asset_info;
result = HAPI_GetAssetInfo( hapiTestSession, asset_id, &asset_info );
assert( result == HAPI_RESULT_SUCCESS );
HAPI_NodeId network_node_id;
hapiTestSession, asset_id, &network_node_id,
assert( result == HAPI_RESULT_SUCCESS );
HAPI_NodeInfo network_node_info;
result = HAPI_GetNodeInfo(
hapiTestSession, network_node_id, &network_node_info );
assert( result == HAPI_RESULT_SUCCESS );
// Get the child node ids.
std::vector< HAPI_NodeId > child_node_ids(
network_node_info.childNodeCount );
hapiTestSession,
network_node_id,
child_node_ids.data(),
network_node_info.childNodeCount );
assert( result == HAPI_RESULT_SUCCESS );
// Create a node.
HAPI_NodeId box_node_id;
result = HAPI_CreateNode(
hapiTestSession, network_node_id, "box", &box_node_id );
assert( result == HAPI_RESULT_SUCCESS );
// Get node id of our merge SOP.
const HAPI_NodeId merge_node_id = child_node_ids[ 0 ];
// First query should return nothing at index 1.
HAPI_NodeId input_node_id;
hapiTestSession, merge_node_id, 1, &input_node_id );
assert( result == HAPI_RESULT_SUCCESS );
assert( input_node_id == -1 );
// Connect the box to our merge SOP.
hapiTestSession, merge_node_id, 1, box_node_id );
assert( result == HAPI_RESULT_SUCCESS );
// Second query should return the box.
hapiTestSession, merge_node_id, 1, &input_node_id );
assert( result == HAPI_RESULT_SUCCESS );
assert( input_node_id == box_node_id );
// Disconnect the box.
hapiTestSession, merge_node_id, 1 );
assert( result == HAPI_RESULT_SUCCESS );
// Thrid query, after the disconnect, should again return nothing.
hapiTestSession, merge_node_id, 1, &input_node_id );
assert( result == HAPI_RESULT_SUCCESS );
assert( input_node_id == -1 );

Full Source Sample

For a full source sample on node creation and manipulation, see the Node Creation Sample.