Voxel Spawners
Last updated
Last updated
Voxel Spawners are used to procedurally spawn foliage on voxel worlds.
First, we need to create a mesh spawner: a spawner stores information about what to spawn, how to spawn it and where it can be spawned.
A mesh spawner uses a Hierarchical Instanced Mesh to render the meshes. Optionally, when digging, you can check for floating foliage instances nearby, and replace them with full actors. This allows to make a tree properly fall when dug under for instance. See Spawn Voxel Spawner Actors In Area.
Create a new mesh spawner:
Open it, and set the Mesh property to the mesh you want to spawn:
Instance Random can be used to send custom parameters to the foliage material. See Sending data to the material below.
Distance between instances in voxel is the average distance we want between our foliage instances. Here, we want to spawn a cube roughly every 5 voxels, so let's set that to 5:
The Actor Settings section is to configure the actor that will be spawned when the instance is floating. Spawning an actor allows to have physics: when you dig under a tree, it will fall.
We can leave that as it is for now.
Instance Settings are used to configure the Hierarchical Instanced Mesh where the mesh will be rendered.
Note that the collisions settings are separate from the actor collision settings: for example you could want to have non-colliding grass that still collides with the voxel world when dug under.
Here, we want our cubes to collide with the player, so we'll leave our collision to BlockAll.
We will tune Cull Distance later on.
Here, you can configure how to spawn your mesh: its scale, rotation and position relative to the spawn positon.
You can also setup some restrictions, such as max angle with the world up (world up is set in the world generator, to allow spherical worlds to be handled differently than flat ones).
A mesh spawner configures how to spawn a single mesh. Usually you want a lot more than that: that's where the Spawner Config comes into play.
A Spawner Config is the link between the voxel world, the world generator and the spawners.
Create a new spawner config:
The spawner config holds few options:
World Type configures how the rays to find spawn positions will be traced. Flat will make them top to botton, Sphere will make them go towards the center of the voxel world.
Word Generator Outputs is to configure the outputs your world generator will have. Outputs can be used to configure the density, materials and height of the spawners.
Spawners is where all the spawners are stored.
Add a new element to it:
A spawner has a few properties.
This is the spawner asset to use - here our mesh spawner
The density we want to use.
We can use a constant value, a world generator output or some material channel.
A world generator output can be used to drive the density based on some noise.
A material channel can be used to drive the density by manually painted data - eg, you can paint the material UVs and use that as density.
Let's leave that to Constant 1 for now.
Spawners are spawned in chunks. This configures their size.
Additionally, for ray spawners, this also configures the resolution of the mesh used for spawning. The mesh is always 32x32x32: if the chunk size is higher than 32, the mesh will have a lower resolution than the actual geometry. In practice, this lower resolution is not noticeable.
Another performance concern is the time taken to detect chunks near the player: if the chunk size is 32, and the generation distance 16384, 512x512x512 = 134217728 potential chunks need to be considered, which will be too long to be real time.
In short:
For dense spawners like grass that is only spawned near the player, it's best to use a chunk size of 32.
For lower density spawners like trees, a larger chunk size can give the same result way faster.
Let's leave it to 32 for now.
The generation distance is how far spawners will be generated from Voxel Invokers. The voxel invoker needs to have the Use For Events property toggled.
Let's set that to 64.
This category holds more advanced properties:
You rarely need to change these.
Your spawner config should now look like this:
Assign it to your voxel world:
you should see cubes on your voxel map!
Try editing your map using the voxel editor tools, and see the spawners update automatically:
Duplicate our mesh spawner, and set its mesh to be a sphere instead.
Add it to our spawner config, and set their spawn distances to 256:
Hit Ctrl F5 to refresh the voxel world.
Our goal here will be to separate the spawn areas of spheres and cubes.
Create a new voxel graph:
Add the following nodes:
and set your voxel world generator to be this graph:
This will give us slightly more interesting hills:
Create a new Graph Output Config:
Add two float outputs to it, named CubeDensity and SphereDensity:
Then, in your voxel graph details (click on the background of the graph) set the output config to the one we just created:
You can now extend the graph to look like this:
This will spawn cubes where the height is more than 10, and sphere where it's below -10.
Note that you can (and should) use any density between 0 and 1, to have more density variations.
In the spawner config, set the World Generator Outputs property:
Then, configure the Cube and Sphere densities as follows:
Update your voxel world (Ctrl F5): you should now see something like this:
In your spawner config, set the Generation Distance to be 1024:
Update your spawners to have a Distance Between Instances of 25 (to not kill your GPU by sending it millions of meshes):
Update the voxel world: notice that the generation now takes several seconds.
To help with that, you can increase the Chunk Size used by your spawners: for instance, let's set it to 512: notice that the foliage generates much much faster.
The downside of this is that the mesh used to trace ray against has a lower resolution: this can cause some slight spawning errors, like floating instances.
To mitigate that, you can use the Local (or global) Position Offset:
If your terrain generator has no tunnels or overhangs, like here, you can use height spawners.
Instead of generating the mesh and tracing rays against it, height spawners will query the height directly from the generator. This is much faster.
Add a new Height output to your graph output config:
In your graph, add a new Height output:
If you have a flat world, the height should be the Height in SetValue(Z - Height). It is very important for the height to not use the Z coordinate, as we don't know it yet.
If you have a sphere world, the height should be the Height in SetValue(VectorLength(X, Y, Z) - Height). It is very important for the height to only use Normalized(X, Y, Z) and to not use the length.
In your spawner config, set the spawners type to Height and the Height Graph Output Name to Height:
Update your voxel world: notice that everything generates much faster, without any floating instances.
Even with a huge generation distance like 16384 (which is 16km with a voxel size of 100!) the generation should be pretty much instantaneous.
In Height Spawners, set your Chunk Size as high as possible for the best performance: if you have a low chunk size with a high generation distance, a lot of time is going to be spent in chunk processing overhead.
If you use ray spawners with a high chunk size, the density might be sampled a bit off from the surface: this might cause issues if you're using painted data as density. Try lowering the chunk size if painted data is not correctly applied as density.