Many ROPs effectively repeat the things passed into them multiple times. Iteration is a way for ROPs that feed into those to vary their behavior for different copies. The downstream operator that is repeating things passes “iteration” numbers upstream in the
Context that is passed between ROPs, and it will vary those numbers for different copies.
Iteration is similar to the “copy stamp” feature in the TouchDesigner Copy SOP, which evaluates its input chain multiple times and makes values available through the
fetchStamp() function for parameter expressions.
Various operators are able to provide iteration values to their inputs.
Some of them will actually run their input multiple times, with a different value each time (which is costly for performance). For example,
radialClone creates multiple copies of its input and merges them together. It has an option to set the iteration values for each of those copies.
instance operator is similar to
radialClone. It repeats its input some number of times, and passes the index of that loop as the iteration value, and then merges the results. Unlike
radialClone though, it doesn’t apply any transformation on its own. It is designed to be used with operators that consume the iteration and use it to transform the instances.
The other more common type of operator that provides iteration values don’t actually run their input multiple times. Instead they decide what iteration value to use based on the position in space. These are much more efficient since they only run their input once. For example,
modulo1D repeats space along an axis, which effectively makes an infinite number of “copies” of that shape. It has an option to pass along the index in that series as the iteration value, so the “copy” in the middle will use 0, the one to the right of that will use 1, and so on, and the one to the left uses -1, etc.
modulo1D also has an option to produce alternating 0 and 1 as its iteration values.
There are several operators that can make use of the iteration values that are passed to them from downstream ops.
The simplest of these is the
iterationField, which is a field operator that returns either the whole iteration
vec4 or a single part of the iteration (x/y/z/w). It can be used as an input to control the behavior of other ops, such as
translate, which has the effect of applying a different amount of translation for each iteration. In that case, it also may need a
floatToVector to convert from a single iteration value to the vector that
iterationSwitch operator takes two SDF inputs, and toggles between them based on the iteration value. It has options for how it handles values outside the 0 to 1 range (either clamping or toggling back and forth).
rangeTransform applies a transform based on a range of settings. It uses the iteration value to pick where in that range of settings it will use. When used with
modulo1D it can do things like rotating each instance incrementally more than the instance before it.
When used with
instance it can be used to place objects along an arbitrary line in space. It’s important to remember though that this can be much less efficient than
modulo1D since it has to run its input separately for each instance.