Scattering is perhaps the most common use case of GraphN, and in this primer, we hope to give you all the info you need to get a full grasp of scattering workflows. For starters, let's set ourselves a few goals:
- Scattering objects on another mesh's vertices.
- Scattering plants on a plane.
- Using weights (blur, curvature, AO, direction, etc...) to mask our scattered objects.
- Scattering inside an object (like asteroids inside a torus).
Before we dive into each goal, let's quickly talk about how scattering works in GraphN: at its most basic form, scattering is about having a set of coordinates and placing objects on those coordinates. It could be scattering grass on a terrain, rivets on mesh vertices, or wooden posts along a curve.
The only thing you need to create a basic scatter setup is the objects you want to scatter, and the positions where you want them to be scattered at.
In this section, we'll explore scattering on the vertices, edges, and faces of a mesh.
Let's start with a simple example: you have a cube, and you want to instance another object on each one of the cube's vertices. This is what the graph would look like:
The node Cube contains our cube, the node Input Mesh essentially converts our container into a geometry structure, and from there, we use the nodes Get Mesh Positions and Get Mesh Rotations to get the positions and rotations of each vertex on our cube. Positions and Rotations are the foundation of GraphN's scattering system: they're basic coordinates that are essential to any scattering workflow, and as such, you'll find them in multiple nodes. The node responsible for instancing our cylinder is Create Instance, which essentially takes the object we want to scatter, in this case, a cylinder, and then positions, rotations, scales, ids, and a mask input. In the screenshot above, we're only giving it positions and rotations, and it does its job just fine with that.
In this other example, we're creating a plane, querying its vertices, and scattering our object on each vertex.
This is of course a fairly simple setup, but you could deform that plane with a Noise Weights node to create more variation, randomize your scale to introduce more visual differences between instances, etc...
In this use case, we rely on the node Scatter Points, which essentially takes a surface like a plane, and fills it with points, while keeping a minimum distance between each point. This gives you a random-looked scatter setup with very few overlapping objects, which is ideal for foliage scattering. In practice, here's a fairly simple graph that shows its result:
The initial result shown in this video is incredibly dense, with millions of plants scattered all around. As soon as we connect our plants (the node with the name _abf5...) to the Density Meshes input of the Scatter Points node, it will use the average size of our plants as the minimum distance between points, and reduce the number of points we have until there's little to no overlap between them.
Another exciting feature of this node is its Vertex Weights input, which allows you to give it any vertex color channel, and it'll use that to drive the scattering. In the screenshot below, we've painted the letters GN on our plane, then proceeded to get our vertex colors, and pass one of the RGB channels to the Vertex Weights input. The result? a nicely controlled scatter setup!
You can read more on the capabilities of this node in its Node Reference page, but needless to say; this node is your best friend for all things world-building. And it's really, really fast!
So far we've explored various ways of scattering, and in this section, we'll look into different methods for removing certain scattered points based on some attributes.
One small node that may come in handy in all the sections below is Invert Mask. It basically allows you to invert any mask you give it. You could for example have a node setup to only get the closest points to a mesh, and this invert mask node will ensure that you get the farthest points. It's small, but important to keep in your arsenal. Most masking nodes tend to have a Reverse checkbox on them to emulate this node's behavior, so only spawn it if your node doesn't have that.
First, let's explore a common use case: you've scattered plants on a rock, but want to remove some of them based on the angle/slope of the rock. This is the result you're looking for:
Here, the node Points Slope essentially takes the Normals output from the Scatter Points node, and gives us a mask of all the points that we've clamped with our min and max angle properties. This mask is then fed to the Mask input of the node Create Instances, and that's about it!
Internally, what we're doing is taking the angle of each point from its normal, checking if it lies within our range, and if it doesn't, we're removing it from our mask.
Next, we want to mask our points based on their Y axis (or height) position. This one requires a few separate nodes, but the process is quite straightforward, and the result predictable:
For starters, we took the Positions output of the Scatter Points node, and fed it to the Break Vector Array node. This node essentially takes all our positions and breaks them into individual X, Y, and Z float array outputs. In this particular GIF, we're using Maya, so the up axis is Y (in UE it's Z), which is why we passed that output to the node Remap.
We remap our Y axis because the position of each point could be anything from -4987.0 to 4597894 or whatever value you can imagine, so the remapping is basically there to reduce all that unknown range from zero to one. This makes it easy for the node Clamp Array to just look at any position that's above or below 0.x, and clamp it. Remapping is a very useful feature whenever your value ranges are uncertain, but you want things to be in a consistent range like 0-1 or 0-100.
Another common masking use case is mesh-based proximity masking: the idea is to get the nearest points to a mesh, or the farthest points to a mesh. It could be that you have a set of trees and want to scatter grass near them, for example. The node Points Near Meshes is there for exactly that: it not only gives you the points that are near your input meshes, but also removes the ones that are underneath it, all while giving you the right parameters to control its effect. Here it is in action:
In short, the node takes our cylinders in its Meshes input, and the Positions output of the Scatter Points node in its Points input. The result? a Mask output like the ones we've shown so far, which means you can plug it right into the Create Instances node, and call it a day!
The Points Near Meshes node leverages a high-performance raytracing API we're using in various other nodes. You can check out the node references for more on those and how they can help you with your scattering work and much more.
Another alternative to Points Near Meshes is the Points Proximity node. This node doesn't rely on meshes, but just points: you give it a set of points A, and another set of points B, and it'll find you the points A that are closest to the points B. To give you a concrete example: here's a setup where we have our scattered plants, and what we want to do is only keep the ones that are close to the input curve we have:
This setup takes our curve as a container and passes it to the node Input Curves, which converts the DCC curve into a GraphN curve structure. From there, we can use the node Get Curves Positions to get all the vertices of our curve. Finally, we spawn the node Points Proximity, and give it our scatter points positions as the source, since we want to mask our plants, then we give it the curve's positions as the target, since that's what we want to mask against. The result? a beautifully masked path! This is one of the most useful nodes for all things scattering, and you can even use it as an alternative to Points Near Meshes. The main difference is that Points Proximity will rely on your vertices when given a mesh, which means that you need to have enough vertices to get accurate proximity results. But it's much, much faster, and therefore more recommended when you don't care about the limits of this node.
In our previous setup, we created a small path with our curve. Here, what we want to do is "blur" the objects, and use the weights given by the blur node as a scale. The result would be that plants that are closer to the curve are small, and the ones farther from it are large. This gives you a nice gradient scale that makes things a tad more realistic:
The node Points Blur uses the same API as the node Points Proximity, making it incredibly fast even when you feed it dense point volumes. In this graph, we've simply extended the graph of the "Masking with Proximity" section with the points node, then gave it two inputs: the first one is a reference node of the Scatter Points node, and the second one is the Mask output of the Points Proximity node.
We're giving it the mask as its weights, and you can think of a mask as an image where the points that are kept are white pixels, and the points that are not kept are black pixels. Points Blur simply blurs them out, giving you some nice gradient scales all over.
This is just one way of leveraging the points blur node for scaling objects; But you could do so much more with it: another usage is blurring your points and masking out all the points that are smaller than x. You can do that masking with the clamp node, and since the blur range is already in the 0-1 range, that gives you a really nice setup to work with!
So far, we've been working with one mask at a time, but you can combine multiple masks, like keeping the mask along curve setup we've done and the mask near meshes setup. To do that, simply spawn the node Mask Operations, and give it both masks you want to blend.
You can switch the order of the mask blending by checking the Invert Order checkbox property, picking any option in the dropdown, or reversing your mask before feeding them to the mask operations node, etc... Needless to say, this isn't just a powerful but also extremely useful node, and its cost is close to nothing, which means you can chain as many mask operation nodes as you want.
Scattering is all about placing points somewhere and instancing your objects on them. "Somewhere" is the biggest challenge, as you often have to rely on various tricks to get just what you need.
Nodes like Mask Operations are key to that, but GraphN provides hundreds of nodes that can all contribute to your scattering needs. We hope to provide enough sample graphs and tools over time to cover all the most common use cases, and we highly recommend that you experiment and share your findings with us on the Discord server. We're always there helping people get the workflow they're dreaming of.