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

Retrieving a Cooked Clip

A CHOP node processes a CL_Clip, contains one or more CL_Track's. A track is a one dimensional array of samples (32bit floating point values). Each track has a unique name associated with it, such as "tx". All tracks within the same clip share the same sample rate, number of samples, start time and end time.

All samples in a track are equally spaced apart, based on the sample rate. The sample rate does not need to match the frame rate of Houdini; motion capture and audio often provide higher sample rates than the default Houdini FPS.

CHOPs Processing

When a CHOP cook occurs, the cooked CHOP may ask for any inputs, which in turn may cook them. This occurs recursively until all uncooked or out-of-date clips in the network above the CHOP have been cooked.

A CHOP has its own CL_Clip associated with it, myClip. This clip is not automatically cleared when a cook occurs. Generally, most CHOPs call CHOP_Node::clearAndDestroy() before beginning any processing on the CL_Clip. Clips are generally entirely recomputed, but because the previous clip is not cleared automatically, partial updates can be done (though this is not recommended).

Note
Do not delete myClip.

CL_Clip data is stored at each CHOP, and is copied or regenerated at node in the network. If a CHOP has its Unload flag set, once all outputs have processed the clip is cleared to save memory.

CHOP cooking is done in a derived version of CHOP_Node::cookMyChop(). The methods CHOP_Node::inputClip() and/or CHOP_Node::copyInput() can be used to grab the input CL_Clip.

Tracks can be processed however you wish - track at a time, all samples with the same index at a time, or groups of tracks at a time (for vectors).

Tracks can be added, renamed or removed from as the clip propagates through the network. The clip can also be trimmed, resampled or expanded as required.

CHOPs Realtime Processing

A CHOP can also cook in "Time Slice" mode, which provides a realtime cooking mechanism for streaming data. Only the samples between the last Houdini frame that was processed and the current Houdini frame are computed. Time Slice mode only works effectively during forward playback. In one cook, all CHOPs in the network will be cooked for the same "time slice" interval.

A CHOP can operate in both realtime and normal modes, and some CHOPs cook in exactly the same way for both modes. Only CHOPs that need to remember state information from previous samples need to process data differently for Time Slice mode (such as velocity, audio samples, samples for a filter window).

To maintain the previous state, a realtime data block is stored for each track in the clip when the CHOP is in Time Slice mode. During processing in a derived version of CHOP_Realtime::cookMySlice(), CHOP_Realtime::getDataBlock() can be called to retrieve the realtime data block, either by index or by name.

The base class of the realtime data block, ut_RealtimeData, does not contain any data other than its name and track index. A derived class must be used to store any data required, and CHOP_Realtime::newRealtimeDataBlock() must be overridden to return an object of that type. Important state information can then be stashed in this object for the next cook.

CHOP Overrides

A CHOP can override any animatable parameter using its export flag. Tracks are matched to channels by name and nodepath. A parameter with an override will cook the CHOP overriding it if necessary (uncooked or out of data). CHOP cooking then proceeds normally, as described above.

Retrieving a Cooked Clip

Accessing a clip from a CHOP is very simple. Call CHOP_Node::getClip() to return a pointer to the node's clip. You must make a copy of this clip if you wish to modify it. The OP_Context pointer passed to getClip() is optional, though if you omit it, it will return the clip from the last cook, even if the CHOP is out of date. This can be useful if you are trying to avoid a recursion error.

{
OP_Context context(time);
// cooks the CHOP if required.
const CL_Clip *cooked_clip = chop->getClip(&context);
// grabs the clip from the last cook (may be NULL if the CHOP hasn't
// cooked yet)
const CL_Clip *last_clip = chop->getClip();
}