Growing Selection Modifier
Applicable to Genome v1.1 and higher
The Magma Loop nodes introduced in Genome v1.1 provide means to perform user-defined iterations, both general and geometry-related. Additionally, a new Iterations parameter was introduced in this version, allowing the evaluation of the same modifier multiple times over its own results.
In the following example, we will take the existing face selection of a geometry object and will select previously unselected faces that are adjacent to the selected ones. Then we will use the Iterations parameter to perform the operation multiple times over the results of the previous iteration to grow, shrink and even animated the effect.
3ds Max provides Grow and Shrink Selection functions as part of the Graphite Modeling Tools, but these can only be applied manually and are not procedural, so they cannot be animated over time or used on the modifier stack to dynamically influence other modifiers.
Test Scene Setup
We will use a simple Plane primitive for our tests, but any mesh with user-defined face selection could be used instead.
To create the scene
- Create a Plane primitive with Length 100.0, Width 100.0 and 20x20 segments.
- Add a MeshSelect modifier, go to Polygon mode and select one quad in the corner of the Plane.
Adding The Genome Modifier
We will need a Genome modifier to perform the selection growth.
- Add a Genome modifier.
- Switch the Iterate Over mode to "Faces"
- Open the Magma Editor.
- Press [Ctrl]+[O] to create an Output node, set it to FaceSelection channel.
- Press [P] to access the Loops category, then press [E] for the FaceLoopByEdge operator.
- Make sure the output socket [Accumulator 1] of the FaceLoopByEdge operator is connected to the Output node's input socket.
- Drag a wire from the Geometry input socket of the FaceLoopByEdge node and release to create a CurrentMesh input node.
- Drag a wire from the FaceIndex input socket of the FaceLoopByEdge node and release to create a FaceIndex InputChannel node.
- Drag a wire from the last [Accumulator 1] input socket and release, then select from the Menu Input>Channel>FaceSelection.
What Is The Accumulator Socket?
It is important to first discuss the use of the so-called Accumulator sockets in Loop nodes.
An Accumulator input is a special socket which can be initialized to a value before the loop is performed (in our case, the FaceSelection value of the currently processed Face will be used).
Then this value is accessible inside the Loop node and is also available as a socket in the Output node of the Loop. After each iteration, the value passed to the Output node on the right side of the Loop Body reappears as the value at the Input node on the left side of the Loop Body. If the flow modified that value, the changes will presist between iterations.
When the Loop node exists, the last value stored in the Accumulator will become the Output value of the Loop node at that socket. In other words, the Accumulator is like a local variable in programming languages that is initialized before the loop and is modified by the loop to produce a return result of the loop.
You can create any number of Accumulators (which appear in [rectangular brackets] as both input and outpit sockets), rename them, reorder them and give them default values or connect them to other nodes to initialize.
In this case, we will use the one default Accumulator 1 socket without renaming it or adding any more Accumulators.
Creating The Loop Body
Now that we know what the Accumulator does, let's use it to set a face selection by accumulating information about the face's neighbors selected state.
- Select the FaceLoopByEdge and press the Edit LOOP Body button to go down one level.
- Inside the loop's body, press [I] for Input and [L] for LoopChannel. This is a special channel input node that accessed data from the neighbor mesh components the Loop operator is iterating over, as opposed to the channels of the current face being processed by the main iteration of the Genome Modifier. For example, if a triangle face has 3 neighbors, the LoopChannel node will access data of each of these neighbors.
- Set the LoopChannel to FaceSelection channel.
- With the LoopChannel selected, press [L] for Logic and [G] for Greater. Change the Value Type of the second socket to Integer because FaceSelection is also an Integer.
- Select the default connection existing between the [Accumulator 1] sockets and press again [L] and [G] to create another Greater operator. Change the Value Type of the second socket to Integer.
- Press [L] and [O] for a LogicalOr operator to be inserted behind the Greater operator. Connect the other Greater operator's output socket to the second input socket of the LogicalOr.
- Since the output of the LogicalOr is a Boolean but we want an Integer, insert a ToInt operator by selecting the LogicalOr, then pressing [C] for Convert and [I] for ToInt.
What Does This Mean?
Let's analyze this Loop's logic.
In the LOOP INPUTS node, the [Accumulator 1] socket will contain the FaceSelection channel value of the current face being processed (as initialized outside of the Loop's Body). If the face is unselected, the value will be 0. If it is selected, the value will be 1.
This value is then compared with 0 and if it is Greater, the Greater node will produce True, otherwise False.
The LoopChannel node will grab the FaceSelection value of the first neighbor face and produce True or False depending on whether it is selected or not.
These two Boolean values will be combined by the LogicalOr operator - if the current face is selected, or the first neighbor is selected, or both are selected, the result will be True. If both faces were unselected, the output would be False.
This Boolean value is then turned into an Integer and passed to the [Accumulator 1] socket in the LOOP OUTPUTS node.
The same as above happens again, but this time the value of the [Accumulator 1] in the LOOP INPUTS contains the value produced by the previous iteration!
So if the current face was not selected before the loop, but the first neighbor was selected, the [Accumulator 1] would be changed from 0 in the first iteration to 1 in the second. Thanks to the LogicalOr operation, this value of 1 will continue through all following iterations.
If the previous iteration did not produce 1, but the current neighbor face is selected, the [Accumulator 1] will become 1 after this iteration, and so on.
Once there are no more neighbors to check, [Accumulator 1] will have a value of 1 if either the current face was selected, or any one of the neighbor faces was selected. This value will be output as the result of the Loop and will be set as the new FaceSelection of the currently processed face in the main Genome modifier iteration.
If neither the current face nor any of its neighbors were selected, the output will be 0 and the face will remain unselected.
Changing The Genome Modifier Iterations
After enabling the >AUTO updating option, the modifier will peform one iteration over all faces in the Plane. Each face that has at least one selected neighbor, or was already selected before the Genome modifier's evaluation, will be selected. In other words, this will grow the selection by just one step, while preserving previously selected faces.
In order to perform a selection growth with more than one step, we would need to run another Genome modifier on top of the current one. Obviously, if we needed to grow the selection by 50 steps, adding 50 modifiers would be impractical.
To solve this, Genome v1.1 provides an Iterations value spinner in the modifier's parameters exposed in the Modify Tab of the Command Panel. This value defaults to 1, but can be changed freely to run the same modifier over its own results many times. The value can also be animated over time!
Changing the value from 1 to 12 will grow the face selection by 12 steps. Setting the Iterations to 0 will disable the modifier and not run it at all.
Here is the result of 12 Iterations:
Selecting Quads Instead Of Triangles
The modifier operates on the Triangle mesh, so the face selection growth is also performed one triangle row at a time. This produces a jagged growing edge on off iterations. For example, 13 iterations on our Plane look like this:
To solve this, we can add a TurnToPoly modifier above the Genome modifier to select the whole quads of the Plane. Note that it will take two steps for another band of quads to get selected.