Functions
Functions in MCG are represented as sub-graphs connected by a square function connector. Functions have inputs, an output, and are primarily used to transform arrays.
Basics
The items of an array can be transformed using mapped connections to chain simple sequences of operations together. Mapped connections must satisfy specific conditions to be valid, and so are not always available. When a mapped connection cannot be made, you can use the For Each operator to apply a function to each item in an array.
A function is a sub-graph connected by a square function connector.
The inputs of a function are the unconnected inputs contained in the sub-graph.
The output of a function is the square function connector on the last node in the sub-graph.
In the example above, the function's input is the unconnected input of Pass Through Pair. The function's output is the result of Spline from Points. In this graph, a new spline is created for each input, and the resulting array of splines is returned in the For Each node's output.
Reading Function Inputs
The type Fn1[T->U]
can be read by decomposing it into three components: Fn1
, T->
, U
.
Fn1
: A shorthand notation which indicates that the function requires one (1
) input argument. A function which requires two arguments begins withFn2
, and so on.T->
: The typeT
to the left of the arrow->
represents the argument type. Single-letter types such asT
,U
,V
,T0
,T1
, as well as theAny
type represent generic types which have not yet been assigned or inferred.On the For Each node, the generic type
T
is shared with the input array typeArray[T]
, meaning that the typeT
of the function's argument must match the typeT
contained in the array. To see this in action, connect anArray[Float]
into the array slot. The typeT
is now inferred as aFloat
in the function's type.U
: The typeU
to the right of the arrow->
represents the function's output type.U
is generic, and since it differs fromT
, there is no constraint between the two types.U
may ultimately be the same asT
, but this outcome is not enforced.Since
U
unconstrained, we are free to create a function which converts an inputFloat
into an outputInteger
. Doing so promotesU
to anInteger
.Note:A function can only output a single type. However, you can use Pairs or Triples to pack different values into one output.
Multi-Input Functions
Operators like Combine require functions with more than one input. Multi-input functions are expressed with the shorthand prefix (Fn2
, Fn3
, Fn4
, etc) along with comma-separated types to the left of the arrow symbol (->
). In the case of Combine, the function Fn2[T,U->V]
requires two generic inputs T, U
, and outputs a generic type V
.
The types T
and U
are shared with the input arrays Array[T]
, Array[U]
, indicating that the first argument must match the type T
contained in array1, while the second argument must match the type U
contained in array2.
Function Argument Ordering
The order of a function's arguments is determined by a depth-first, top-to-bottom traversal from the function's output towards its inputs. The graph below has been labeled with the traversal order. During the traversal, nodes which have already been visited are skipped.
You can connect a Pass Through Any operator to a function connector to diagnose a function's signature while you build it.
As a (convoluted) exercise, the graph below illustrates how Ignore First can be used to control the node traversal (and therefore the argument ordering) explicitly. Note that Ignore First evaluates its first branch but discards the result, then returns the result of its second branch. Ignore First and Ignore Second can be used to control function argument ordering, or to control the order of execution of operators which have side-effects in 3ds Max (ex: Clone as Instance, Create Editable Mesh, Create Editable Spline, Evaluate MAXScript).
Filtering
The Filter operator requires a one-argument function which returns True if the given item should be preserved in the output array. In the graph below, the Filter only keeps the vertices whose Z component is greater than or equal to 0.0.
Parallel Functions
For computationally expensive operations, consider using the parallel operators For Each Parallel and Combine Parallel to pool the iterations across the available cores of your CPU.
Keep in mind that these parallel operators are not a universal solution to improving the speed of your graphs. If your arrays are small, the overhead of initializing the underlying parallelization structures may slow your graphs down. As a general rule, we advise you implement your logic with simple For Each nodes or mapped connections, and afterwards optimize with For Each Parallel where appropriate.
If an exception is thrown during a parallel operation, or if the graph terminates prematurely by means of an Exit If node, a Cancellation Token message will be printed to the MAXScript Listener.
Avoid the following operators during parallel operations. These affect the single-threaded 3ds Max layer, which will likely lead to instability.
- Evaluate MAXScript
- Clone as Copy
- Clone as Instance
- Clone as Reference
- Clone Hierarchy as Copy
- Clone Hierarchy as Instance
- Clone Hierarchy as Reference
- Create Editable Mesh
- Create Editable Spline
- Select SceneNodes
- SceneNode Set Pivot Offset
- SceneNode Set World Position
- SceneNode Set World Transform
- At Time Context
- Print Message
- Trace
- Trace Array
- Trace Array Range
- Trace RigidBody
- Trace with Label