HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Dependencies

Topics

Name Dependencies

Name dependencies indicate to Houdini that some node or parameter relies on the name of some other node or parameter. For example, suppose we have a node path parameter. Then when the node which the path parameter refers to is renamed, Houdini correspondingly updates the value of the path parameter. These dependencies are typically static and are usually specified by marking the string parameter using one of the following PRM_TypeExtended options:

  • PRM_TYPE_DYNAMIC_PATH
    Specifies a node path parameter with a node chooser icon button. If this is used, then you should additionally specify the desired node type for the path parameter via one of the predefined PRM_SpareData objects such as PRM_SpareData::objPath or PRM_SpareData::sopPath.
  • PRM_TYPE_DYNAMIC_PATH_LIST
    Similar to PRM_TYPE_DYNAMIC_PATH except it accepts a list of node paths. For name dependencies to work with lists, you also need to use PRM_STRING_OPLIST instead of PRM_STRING. The reason why these dependencies should be established statically (as opposed to dynamically at cook time) is because this updating needs to happen even when no nodes have been cooked (eg. right after loading a scene file in hbatch).
static sopParmName("objpath", "Object Path");
SOP_MyNode::myTemplateList[] = {
// ...
1, &sopParmName, 0, 0, 0, 0, &PRM_SpareData::objPath),
// ...
};

Data Dependencies

In Houdini, cooking evaluation takes place as a data dependency graph. The edges of this graph are typically the wires that are shown in the network view pane. However, if a node cooks the data of some other node via some other means (eg. via the value of some parameter like the Object Merge SOP), they must explicitly state this dependency by calling OP_Node::addExtraInput(). This lets Houdini know that when the other node's data changes, this node also needs to be recooked.

Elements in the UI express an interest on the nodes so that when the nodes are dirtied, they are notified to recook. When a parameter changes, everything in the graph that depends on the parameter's data is dirtied accordingly. Then when the UI element recooks the interested node, the graph is traversed, cooking the nodes which are dirty.

Since data dependencies can occur depending on the value of parameters, the data dependency graph has the potential to change every time a node is cooked, or a parameter is evaluated. For this reason, extra inputs are cleared as soon as they are traversed upon the dirty propagation. Thus, it is important that if a node depends on another node, it must call OP_Node::addExtraInput() upon every cook.

SOP_MyNode::cookMySop(OP_Context &context)
{
fpreal t = context.getTime();
UT_DMatrix4 xform(1.0); // identity
OBJ_Node * obj_node;
UT_String obj_path;
// ...
evalString(obj_path, "objpath", 0, t);
obj_node = findOBJNode(obj_path);
if (obj_node)
{
obj_node->getLocalToWorldTransform(context, xform); // use its data
addExtraInput(obj_node, OP_INTEREST_DATA); // tell Houdini
}
// ...
}

The parameters of a node are marked as used for cooking by default. This means that the node's output data implicitly depends on the value of its parameters. Therefore, nothing extra is needed when evaluating its own parameters. However, if your node evaluates some other node's parameter, then you must explicitly call addExtraInput() to mark this dependency. The following code snippet illustrates this using an alternate form of addExtraInput().

fpreal t = context.getTime();
int pi = other_node->getParmList()->getParmIndex("r");
int vi = 1;
fpreal ry = other_node->evalFloat(pi, vi, t);
addExtraInput(other_node, pi, vi);

For DOP simulations, there is a special micro-node, obtained by DOP_Parent::simMicroNode(), that is used to keep track of dependencies on simulation output. If your node or parameter depends on the data returned by methods defined in DOP_FullPathData.h, then you should add an extra input. The following is an example.

if (DOPfindDataFromPath(objpath, dopdata, context.getTime(), this))
{
addExtraInput(dopdata.myParent->simMicroNode());
// ....
}