Note: The interface in this tutorial applies to MCG 2017. The interface in MCG 2018 has been revised to a new node naming scheme.
In many cases, procedural effects rely on the world space position, rotation, and scale of other objects in the scene. For example, you might want to hang wires between the vertices of two separate objects, or you might want to model a plant using point helpers in the scene. In this post, we’ll cover how to achieve these kinds of effects using MCG.
Let’s start by understanding the concepts of “local space” and “world space”, and how they relate to MCG. Open the Max Creation Graph Editor, create the following graph, and save it as SpaceTest.maxtool. In the graph below, we’re using the IgnoreSecond and Sequence operators to create a box mesh, and to print its vertex positions.
To see it in action, go to the “Create Tab > Max Creation Graph > SpaceTest”, and click on the grid to create a SpaceTest cube. When you move it, rotate it, or scale it in the scene, you’ll notice that the position of each vertex is printed to the MaxScript Listener (“Scripting > MAXScript Listener”).
Here, we see that the cube’s “Local Space Vertices” are always defined in the same way, namely that they surround the local point [0,0,0]. What’s more, we have enough information inside the graph to calculate the “World Space Vertices”, which correspond to the position of each vertex relative to the scene’s origin.
Before we move on, let’s break down some important terms we’ll be using as we continue this post:
- The term “space” is interchangeable with: “coordinate system”, “coordinates”, “frame of reference”, and “basis”. You might encounter those last two terms in math-oriented articles on Wikipedia.
- The concept of “local space” can be visualized as the MCG tool’s coordinate system. In the example above, the box’s vertices are always defined in relation to the same local point: [0,0,0], regardless of how the cube is eventually positioned in the scene. In fact, the most important thing to remember from this tutorial is that the mesh created by an MCG geometry (or an MCG modifier) must always be defined in relation to its local origin. In a few moments, we’ll see how this fits into the greater scheme of things.
- The concept of “world space” is also referred to as “scene coordinates”, or the “global coordinate system”. You can visualize the origin (i.e. [0,0,0]) of the world space as the center of the grid in your viewport.
Now, we saw that we could convert the cube’s local vertex positions into their equivalent world positions. To do that in our graph, we need to use the “Geometry: Matrix” implicit parameter. Note that if we were working inside an MCG modifier, we would have used the “Modifier: Matrix” implicit parameter instead.
This matrix is used to convert a point from its position in local space into its position in world space. The inverse of this matrix does the opposite. It converts a point from its position in world space into its position in local space.
If you feel like your head is spinning with all that information, here are the important points to keep in mind so far:
- The mesh created by an MCG geometry (or an MCG modifier) must always be defined in relation to its local origin.
- “Geometry: Matrix” can be used to convert from local coordinates into world coordinates. This matrix should be used if you need to answer the following question: “Given a in the tool’s local space, what is its equivalent in world space?” Recall that this is how we printed the cube’s world space vertices above.
- The inverse (InvertMatrix) of “Geometry: Matrix” can be used to convert from world coordinates into local coordinates. This matrix should be used if you need to answer the following question: “Given a in world space, what is its equivalent in the tool’s local space?”
With these points in mind, it’s time to fasten your seatbelt and hang onto your hat, because we’re going to make spaces collide. When you’re ready, create the following MCG geometry graph, save it as LocalBoxWorldBox.maxtool, and evaluate it.
Under the “Create Tab > Max Creation Graph”, create a LocalBoxWorldBox geometry in the scene. You’ll see two boxes appear: one box (Box1), which responds to your changes in position, rotation and scale, and another box (Box2), which remains fixed at the world origin.
If you’re a little bit freaked out, rest assured that this is a natural reaction, and that we’ll gently unwind the apparent sorcery at work here.
First, remember that the mesh created by an MCG geometry (or an MCG modifier) must always be defined in relation to its local origin. For Box1, fulfilling that requirement is simple - we can leave it as-is since we’re interpreting its definition in local space. This way, it will respond to changes in position, rotation, and scale in the scene.
For Box2, we’ve chosen to interpret its mesh definition in world space (i.e. centered around the world origin). The same rule still applies though - we need to redefine it in relation to our tool’s local origin. To do that, we need to answer the familiar question: “Given a mesh defined in world space, what is its equivalent in local space?” If we look back at point 3 above, we realize that the answer to that question is to transform the mesh by the inverse of “Geometry: Matrix”.
At this point, we’ve shown how to convert a mesh’s coordinates from world coordinates into local coordinates. The last piece of the puzzle for creating world space effects in MCG is to understand how to work with other meshes in the scene.
Consider the following problem: you want to decorate a geosphere by placing a box on each of its vertices, and you want to work in the least destructive way possible. That is to say, you don’t want to affect the sphere’s geometry in any way (including its existing topology, UVs, material ids, smoothing groups, map channels, and per-vertex data channels).
Given that we want to act in the least destructive way possible, it’s best to decorate the sphere using an MCG geometry instead of an MCG modifier. Using a modifier here is less desirable because it would increase the complexity of the tool; you would need to adapt the new mesh’s UVs, material ids, smoothing groups, map channels, and per-vertex data channels to account for the current sphere’s mesh as well as the the new box meshes, since they would all be part of the same mesh. To avoid all that complexity, we’ll use an MCG geometry.
Create the following graph and save it as BoxesOnVertices.maxtool. Note that since we want to work with an object in the scene, we’ll need a “Parameter: INode” to let us pick that object from our tool’s rollout. We’re using a CheckNodeValidity operator here to make sure the node is valid, and to exit the graph preemptively if the node is invalid.
Evaluate the graph, then go to “Create Tab > Max Creation Graph > BoxesOnVertices”. Create a BoxesOnVertices object in the viewport. Nothing will be created until you set the “targetObject” as the geosphere (or any other object with vertices in the scene).
For now, none of the boxes are attached to the sphere. However, we can still see that their positions are in the same relative position as the sphere’s vertices. We’re on the right track, and it’s time we started talking about “spaces” again.
There are three spaces to consider here:
- Our tool’s local space - this is the MCG geometry’s coordinate system in which we have to define our output mesh.
- The world space - the global the coordinate system.
- The node’s local space - this is the coordinate system in which the sphere’s mesh is defined.
To get the effect we’re looking for, the idea is to first convert the sphere from the node’s local space into world space, create the boxes in world space, and then convert them into local space. More concretely, here’s how we can achieve that in our graph:
- Convert the sphere’s mesh from the node’s local space into the world space. Note that we’re using the node’s “WorldTransform” to perform this conversion. This matrix converts from the node’s local coordinate system into the world coordinate system.
- Create the boxes using the sphere’s vertices in world space.
- Convert the combined box meshes from world coordinates into our local coordinates using the inverse of “Geometry: Matrix”.
To make sure you’re on the right track, your BoxesOnVertices graph should now look like this:
As a workaround to an existing MCG bug, since we just added the “Geometry: Matrix” implicit parameter into our graph, we need to delete the existing BoxesOnVertices object currently in our scene. This issue is caused by the fact that the old BoxesOnVertices object in the scene wasn’t aware it required the “Geometry: Matrix” implicit parameter when it was created. From here on out, any other BoxesOnVertices objects will “know” they need to use the Geometry: Matrix, so you don’t have to keep deleting and recreating these objects every time you iterate on your tool.
Now, when you create a BoxesOnVertices object and select a target object, the boxes will always be aligned to the world space position of the target’s vertices. Modifying the target object will update the boxes automatically, despite the fact that they are defined as a geometry and not as a modifier.
If you’ve got an eye for detail, you’ll notice that as you rotate the target object, the boxes will remain aligned to the same axes. This is happening because we’re defining them in world space before converting them into our tool’s local space.
To make them follow the rotation of the object, we can adapt our graph and simply define our boxes in the node’s local space before applying the space transformations (node local ? world ? tool local). Here’s what that looks like:
When you evaluate this graph, the boxes should now respond to changes in rotation on the target object.
We can do a bit of matrix magic and clean up the last part of our graph to reduce the number of mesh transformations. If you’re working with large meshes, transforming each one repeatedly can get computationally expensive, so it’s much faster to multiply two matrices and transform the mesh only once. Recall that we can apply space transformations to matrices by multiplying them together. As such, we can condense the graph to the following construction:
In conclusion, now that you have a sense of how world space effects are done in MCG, here are two tools you can pick apart. You can download and install these .mcg tools from the zip file linked at the bottom of this post. These .mcg tools contain compounds that I created specifically for this tutorial, so you might not find them in your default operator list. Once you've installed these .mcg's, (Scripting > Install Max Creation Graph (.mcg) Package), you can open their respective .maxtool files from: C:\Users\\Autodesk\3ds Max 2016\Max Creation Graph\Tools\Downloads.
Creates a world-space wire between the vertices of two objects.
- Create two geometry objects in the scene.
- Create a Wire object from “Create Tab > Max Creation Graph > Wire”.
- Select both geometry objects to create the wire.
- Adjust the gravity and tension spinner values to your liking.
- Adjust the vertex spinner values to change the start and end vertices.
- Add a Cap Holes modifier to close the hole at the start and end of the cylinder.
Creates world-space geometry using the position, rotation, and scale of point helpers in the scene.
- Create two (or more) point helpers in the scene via Create Tab > Helpers > Point. To visualize the effect of these helpers more clearly, enable “Axis Tripod” and “Box”.
- Change your manipulate mode from “View” to “Local” when you want to position, rotate, and scale these helpers.
- Create a BezierGeo object from “Create Tab > Max Creation Graph > BezierGeo”.
- Using the “helper#” pickbuttons in the rollout, select the helpers in the order you want your geometry to “grow”.
- If the geometry looks a bit strange, decrease the “handleMult” value until it looks like a nice 3d bezier curve.
- Adjust the position, rotation, and local scale of each helper to change the BezierGeo object.
- Use the “progress” spinner to animate the growth of your BezierGeo.
- You can toggle "showBoxes" to display boxes instead of a cylinder.
Instructions: Extract WorldSpaceEffects.zip anywhere on your filesystem. In the extracted directory, you’ll find the following .maxtool files which you can open in the Max Creation Graph Editor and evaluate (Ctrl+E): SpaceTest.maxtool, LocalBoxWorldBox.maxtool, BoxesOnVertices.maxtool. These are MCG geometry objects which can be created from the Create Tab > Max Creation Graph dropdown. You will also find Wire.mcg and BezierGeo.mcg, which you can install via Scripting > Install Max Creation Graph (.mcg) Package. The usage of these tools is described in the sections above.