HDK
|
This example is a copy of the Spring CHOP. It adds lag and overshoot motion to a position channel, as if the motion were resisted by a spring. The Spring CHOP can work in Time Slice mode for realtime processing.
These code fragments can be found in the example HDK code in CHOP_Spring.C.
These headers are required for all HDK OPs.
These headers are generally required for all CHOPs.
UT_Interrupt is used for querying if the user interrupted the operation while cooking. UT_IStream is used by Time Slice mode to save out intermediate data across sessions.
This code defines the parameter dialog for the Spring CHOP. In addition to the spring constants, there is an option to model the input channel as either position or force, and an option to specify the initial spring conditions with parameters or by computing them from the initial input samples.
Most CHOPs have the C and NC local variables defined for the currently cooking channel and the total number of channels. These values are modified by the cook method and stashed in member variables in the class. To optimize the number of parameter evaluations, myChannelDependent
is used to determine if the spring parameters need to be re-evaluated for each track.
The Spring CHOP derives from CHOP_Realtime rather than CHOP_Node, which adds the ability to cook in Time Slice mode. mySteady
is used as part of time slice cooking.
First, we'll look at the normal, non-timeslice cook method.
The beginning of the cook method evaluates all parameters, copies the structure of the input clip into the output clip, and determines if any errors occurred.
It also check to see if any of the spring constants used the local variable 'C', which would require them to be re-evaluated for each track.
The next part of the cook method begins looping over each input track. If a track is not scoped, it is copied as-is and the rest of the processing is avoided. Otherwise, the spring constants are re-evaluated if required ('C' used) and the initial conditions are computed if the user isn't specifying them via parameters.
The last part of the code loops over the samples in the input track and applies the simple spring equation to them, assigning the results to the output track.
Now, the next part of the file deals with the realtime processing of the spring effect. If you are creating a filter that doesn't work in time slice mode, or works in realtime without any changes to the cookMyChop()
method, then you can skip to the bottom where the node is registered. Otherwise, read on.
This helper class defines the Spring CHOP's instance of a realtime data block. It must derive from the ut_RealtimeBlock
base class. This class is used to stash intermediate data that is needed between cooks in order to keep the effect running seamlessly between realtime updates. In this case, we need to stash the previous two displacements.
A realtime data block also needs load and save methods to store these conditions in the hip file, so that the CHOP's values don't explode off to infinity or enter some other bad state when the file is opened and the CHOP cooked again (user input, like audio, controller motion or a periodic timer).
Realtime CHOPs can reach a 'steady state' where they can stop cooking every frame. A change in the input is then needed to start the CHOP cooking again.
In this example, a flag is used to indicate when a steady state has been reached. With a spring, it's when the springing motion has settled to a rest position.
The realtime cook method is called cookMySlice() rather than cookMyChop(). In addition to the context, the cook frame interval is passed as well, through start
and end
.
The initial part of the realtime cook method looks almost the same as the normal cook method, although we don't copy anything from the input clip. The output clip is already set up correctly for the interval required.
The next part of the code which respects scoping, and re-evaluates the spring constants if C is used, also looks similar.
Where the initial conditions come from is quite a bit different, however. The CHOP_Realtime::getDataBlock() method is used grab the realtime data block for this track (possibly creating one if it doesn't exist). The initial conditions are then taken from there.
Again, the spring equation is run on the input samples and written to the output track.
When all the samples have been processed for the track, the data needed to smoothly continue the algorithm are written to the realtime data block. This ensures that the next iteration of the realtime cook gets the proper initial conditions.
This method must be overridden from CHOP_Realtime in order to create a new realtime data block for getDataBlock()
in cookMySlice()
. Realtime data blocks are cached between cooks, so it is only called when an existing data block cannot be found for a track.
In this example, the initial conditions for the spring are set using the parameters or computed from the input track, in the same way that they were in cookMyChop()
. These conditions are stashed in a new ut_SpringData
subclass of a realtime data block.
This registers the CHOP with Houdini as a 1 input filter named "HDK Spring".