Note: The interface in this tutorial applies to MCG 2016/2017. The interface in MCG 2018 has been revised to a new node naming scheme.
If you’ve started working with MCG, you’ve likely asked (perhaps out-loud) “What in the world is that little square function connector?” The goal of this post is to demystify this connector and to get you comfortable with using it.
Let’s start by imagining the Map operator as a very particular wizard. He’ll work for you, provided you abide to his two conditions:
1. He’ll only work with arrays. If you would like him to work on a single item, you’ll have to package it into an array containing that one item.
2. You need to give him one formula (i.e. a function), which he’ll apply to each item in the array.
When he’s done, he’ll give you a new array containing all the transformed items. In other words, the wizard “maps” a function to each item in the array and returns a new array of transformed items.
Here’s a more concrete example - in the following graph, we’re supplying the wizard with an array of five numbers: [0, 1, 2, 3, 4]. We’re also providing a formula, which is simply to “add 1 to the input number”. The wizard waves his wand, and *poof*, the formula is applied to each number. The result is the transformed array of numbers: [1, 2, 3, 4, 5].
Adding 1 to each number in an array has its uses, though it doesn’t paint the most interesting picture. As a slightly more interesting example, let’s look at the following MCG modifier, which creates boxes on a mesh’s vertices.
As a quick summary of the graph, the MeshVertices operator returns the mesh’s vertex positions as an array of Vector3’s. The Map operator takes this array, and applies the input function (or the “formula”), which can be read as follows: “Create a box, and offset it using the given Vector3”. Once all the boxes are created and properly offset, they are all combined as a single mesh. This mesh is then combined with the original mesh, and passed to the graph’s terminal operator, the Output: modifier node.
Now that we have an idea of what the function does, we can take a closer look at its “syntax” – in other words, what makes a function a function?
To start, you can spot a function by looking for a connection between two function slots:
The operator at the beginning of the connection defines the function’s output type. In this case, the output type of the OffsetMesh operator is a TriMesh value, which means that the whole function will output a TriMesh. If the output type is “any” (which is the case in our first example with the “Add” operator), the type checker will attempt to infer the function’s output type automatically (this occurs when you select either: Build > Validate, Build > Evaluate, or when you press CTRL+E).
With the output of the function in hand, you can step backwards through the graph to identify all the nodes whose values are required to calculate the function’s output. In more elaborate functions, this “requirement path” usually branches out, and can be more accurately described as a dependency hierarchy.
In this function, we can see how the OffsetMesh operator requires the value of CreateBox, which itself requires the value of the “box size” Parameter. We’ll refer to this dependency hierarchy as the function’s “body”, since all these nodes are required to compute the function’s output.
The last step is to identify the function’s input(s). You can recognize a function’s inputs by the unconnected input slots within the function body. In this case, the function body contains only one unconnected input slot, namely the Vector3 “offset” on the OffsetMesh operator. The function therefore accepts a Vector3 as an input, which is automatically “plugged” into the offset slot.
With all its parts identified, we can summarize that the function:
1. Takes a Vector3 as an input
2. Creates a box and offsets it using the Vector3 input
3. Returns the box as a TriMesh.
The Map operator makes use of this function to transform the array of Vector3’s into an array of TriMeshes.
Now that we have an idea of how to “read” a function in MCG, in the next part, we’ll look at some techniques to help you build MCG graphs and functions from scratch.