HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Working with Parameters

Topics

Basics

The OP_Parameters class (parent of OP_Node) provides basic functionality for using parameters. It contains a PRM_ParmList object which owns an array of PRM_Parm objects. Each PRM_Parm object can have a number of components. Each parameter component has an optional channel (CH_Channel class). For example, the Translate parameter "t" has 3 components with channel names "tx", "ty", and "tz" respectively.

Given a node, parameters can be looked up either by name or by index. The recommended approach is to always look up parameters by name. The parameter name to index translation is fairly fast since it uses hash tables.

The value of a particular parameter can be obtained using the various parameter evaluation functions in OP_Parameters. To set the value on parameter component, use the various parameter setting functions.

In both cases, it is also necessary to supply the evaluation time. Often times, this information is already given to you as explicit function parameter, or indirectly via an OP_Context parameter. If given an OP_Context object, simply use OP_Context::getTime(). In absence of this, you can obtain the current evaluation time via the CHgetEvalTime() function.

When evaluating parameters, there are always two forms of each eval function: one explicitly supplying the "thread" id parameter, and another that simply uses SYSgetSTID() as the thread id. If you have an OP_Context parameter, you can use the explicit thread id version of the eval function by passing it the return value of OP_Context::getThread().

void
someFunction(OP_Node *node, OP_Context &context)
{
float now = context.getTime();
float tx;
// evaluate the translate x parameter
tx = node->evalFloat("t", /*component_index=*/ 0, now);
// set the translate y parameter to 2.5, creating a keyframe if a channel
// exists
node->setFloat("t", /*component_index=*/1, now, 2.5, /*set_keyframe=*/true);
// set the translate y parameter following channel references first, but do
// not create a keyframe if the final parameter component contains a
// channel
node->setChRefFloat("t", /*component_index=*/1, now, 2.5);
}

Multi-Parms

Multi-parms are dynamically sized parameters. Each multi-parm has a variable number of child instances. Each multi-parm child instance itself consists of a fixed number of parameters (defined by the same array of PRM_Template objects). To determine how many child instances a multi-parm has, simply evaluate the multi-parm as an integer value. In order to identify the instances, the token name of the child parameters must include a pound (#) character when the multi-parm is being defined. If the child multi-parm instance also contains a multi-parm, then the instance parameters of the "nested" multi-parm must include an additional pound (#) character. In general, a parameter token name must have exactly one pound (#) character for each of its parent multi-parms.

When new multi-parm child instance parameters are created, the pound (#) character is substituted with the instance index as the actual parameter name. Note that the starting index can be any arbitrary number but it is usually 0 or 1.

In OP_Parameters, there are Inst versions of the eval and set functions specifically geared for multi-parms (eg. OP_Parameters::evalFloatInst() and OP_Parameters::setFloatInst()). These functions take an array of instance indices (inst parameter), along with the length of the array (nestlevel parameter). The nestlevel parameter for these functions default to 1 so that for non-nested multi-parms, we can simply pass it the address of our single instance index.

Let's take an example from the BlendShapes SOP which has a multi-parm named "nblends" (label "Blends"). Its multi-parm instance has just one parameter named "weight#".

void
someFunction(OP_Node *blend_sop, OP_Context &context)
{
float t = context.getTime();
int num_instances = blend_sop->evalInt("nblends", 0, t);
int start_idx = blend_sop->getParm("nblends").getMultiStartOffset();
int instance_idx;
// evaluate all multi-parm instances
float * weights = new float[num_instances];
for (int i = 0; i < num_instances; i++)
{
instance_idx = start_idx + i;
weights[i] = evalFloatInst("weight#", &instance_idx, 0, t);
}
// ... do something with weights ...
delete [] weights;
// add a new multi-parm instance with a 0.2 weight value
blend_sop->setInt("nblends", 0, t, num_instances + 1);
instance_idx = start_idx + num_instances;
blend_sop->setIntInst(0.2, "weight#", &instance_idx, 0, t);
}

Ramp Parameters

Ramp parameters are multi-parms that semantically represent a lookup function. Given a parametric value between 0 and 1, the ramp lookup returns an interpolated value using an array of "ramp points" as a curve. Ramp parameters have a special graphical user interface in the parameter pane and also have a standardized child instance parameter list where each instance contains the data for a ramp point. There are two different ramp types: color or float. They differ in their parameter pane user interface as well as in their instance parameter list. In scripting, and in the HDK, they can be manipulated like any other multi-parm.

To perform a lookup using a ramp parameter, OP_Parameters::updateRampFromMultiParm() provides a means of marshaling the data into a UT_Ramp object. If you modify a UT_Ramp object, you can transfer it back to the ramp parameter via OP_Parameters::updateMultiParmFromRamp().

void
someFunction(OP_Node *node, OP_Context &context, float u)
{
float t = context.getTime();
UT_Ramp ramp;
float values[4];
node->updateRampFromMultiParm(t, node->getParm("ramp_name"), ramp);
ramp.rampLookup(u, values);
// for float ramps, only values[0] will contain valid data
// if you modify UT_Ramp, you can marshal it back to the ramp parameter...
node->updateMultiParmFromRamp(t, ramp, node->getParm("ramp_name"), false);
}