Voxel Plugin
2.0p-304
2.0p-304
  • Home
    • Roadmap
    • Release Notes
  • Getting Started
    • Installing Voxel Plugin
    • Using MetaGraphs
      • Using the MetaGraph Preview
      • Finding the Right Nodes
      • Variables and Parameters
    • Step-by-Step Guides
      • Getting Started with Smooth Terrains
      • Getting Started with Blocky Terrains
      • Getting Started with Foliage
      • Getting Started with Materials
  • Landmass & MetaGraphs
    • Design Philosophy
      • What are Landmass & MetaGraphs
      • A Technical Exploration of MetaGraphs
    • Deep Dives into MetaGraphs
      • Passing Data to Materials
      • Working with Curves
      • Working with Landmass
        • Using Landmass Height Brushes
        • Scale and Resolution for Landmass Brushes
        • Complex Usecases for Landmass Brushes
      • Choosing the right Chunk Spawner
      • Using Height Canvases
      • MetaGraph Macros
      • Floats and Density
      • Buffers and Uniforms
    • Optimizing MetaGraphs
      • Utilities for Performant Graphs
      • Memory Usage & Render Performance
      • Profiling Generation Times
    • Extending MetaGraphs through C++
Powered by GitBook
On this page

Was this helpful?

  1. Getting Started
  2. Step-by-Step Guides

Getting Started with Smooth Terrains

This guide explores the basic functionality of MetaGraphs by using noise and Landmass brushes to create a smooth (Marching Cubes) terrain.

PreviousStep-by-Step GuidesNextGetting Started with Blocky Terrains

Last updated 2 years ago

Was this helpful?

This guide was made using Unreal Engine 5.1, with a plugin release from early December.

For a more detailed understanding on how a mesh is generated from input data, we strongly recommend watching . In Voxel Plugin the density field is generally an approximate distance to the nearest surface in world units (cm in stock Unreal), so we often refer to it as a “distance field”.

1. Preparing your Graph and Voxel Actor

To start off, create a MetaGraph asset from the content browser right-click menu.

Select the “Empty” starting point from the pop-up window, and then press “Create”.

Drag the created MetaGraph asset from the content browser into the editor’s viewport - this will create a Voxel Actor in the scene with the newly created MetaGraph assigned as generator.

Double-click the graph asset to open the MetaGraph editor. With the graph asset open, right-click and search for "On Construct" in the search bar. Click the matching result to place it as a node. Next, drag out from the "On Construct" node and let go on open space in the graph to again open a search menu.

More information on how to find the right nodes to use can be found here: Using MetaGraphs

In this search menu, have a look at the available options. The Flow Control and Misc categories are not useful for generation, as they just contain utilities. TThat leaves us with the Chunk category. If we expand this, we get a few options. In this case - and for most terrains - we'll be choosing the Spawn Chunks by Screen Size node, as it works in 3D and creates LODs.

For an extended explanation on Chunk Spawners and when to use which, see the Choosing the right Chunk Spawner page.

Having placed a chunk spawner, there are two visible execution pins. The top one can be used for creating more chunks, and the bottom one is used for the instructions on what each chunk created by this node should do. In this case, to start creating instruction on what these chunks should look like, drag out from the second pin.

To render the terrain, a mesh is required. Open the Mesh category in the search panel, and add a Create Mesh Component node. The Spawn Chunks by Screen Size node will call this for every chunk, resulting in a procedural mesh component being created per chunk.

If desired, Collision and Navigation can be created per chunk (potentially with a different chunk spawner for different LODs) in the same way.

In this case, let's add a Spawn Chunks by Range node and make that generate collision for the mesh. This will create an area of LOD0 collision around the player at all times, avoiding physics glitches that come with colliders changing with LODs. Try finding and placing these nodes by yourself, and then use the image below to check if your graph is correct.

For Create Collision Component, we need a Collider and a Body Instance. Dragging out from the Collider, place a Create Collider from Marching Cube Surface node.

For the Body Instance (often called "Collision Preset" in the engine UI), dragging out will give no options other than Flow Control and Misc. This is because Body Instance is a complex struct, which needs to be configured as a variable. In the search menu, pick the Promote to Local Variable option. Its default collision values are fine for this example.

More information on working with variables and similar UX topics can be found on the Using MetaGraphs page.

The graph should now look mostly like this:

With this, the groundwork for the world generation has been done. From here, all that is left is to actually tell these chunks what their mesh surfaces need to look like. That means that from this point on, the Create Collider and Create Mesh nodes will take the same surface inputs.

Start by dragging out from the Surface pins on either the collider or the mesh node, and placing the Generate Surface node. Make sure to connect the Surface pin on the newly placed node to both the other nodes - otherwise your collider or mesh will not generate. Once again, the default settings are fine, and we will only worry about the top-most pin; Density.

The Density pin is a different kind of pin from the others in this graph so far. Rather than having the standard round pin icon, it instead has a square as pin icon. This signifies that the Density pin is a Buffer, rather than a Uniform like all the other pins so far. A Buffer is simply a stack of data: that single pin represents all the density points within a chunk at the same time, rather than just being a single value.

If that Buffer explanation makes little sense, just know this:

  • If a value changes based on position, it is almost always a Buffer.

  • If a value is the same for every position, it is almost always a Uniform.

Buffers can only be used as an input for Buffer pins specifically. Uniforms can be used as an input for both Buffer and Uniform pins.

If you want to learn more about buffers and uniforms, have a look at the Buffers and Uniforms page.

In this graph, the intent is to create a basic heightfield terrain. Drag out from the Density pin, and place the Make Density from Height node. This converts a height input to a density, or distance field, output. Drag out from Position to place a Get Position 3D node. Next, in order to start defining the shape of the height field, drag out from Height. Before doing anything with noise, though, place a Query 2D node. This will tell the graph that this section of the logic is not volumetric, and makes it significantly cheaper to run.

More information on Query 2D and other nodes like it can be found on the Utilities for Performant Graphs page.

Now it is time to place a node. Drag out from Query 2D and place an Advanced Noise 2D node. Drag out from its Position input (note that it takes a blue position, a Vector2, due to its 2D nature, rather than a yellow Vector3) and place Get Position 2D.

At its default settings, this node runs ten octaves (a technical word for layers) of Perlin noise, with 200 meters (amplitude times two) of height difference between its lowest and highest point, and its large shapes something like 1000 meters apart (feature scale). Note that all world units are specified in Unreal Units, which equates to centimeters.

Right-click the Value output on the noise node, and select Preview pin. This will draw the resulting height from this node in the preview in the top-left of the graph. The graph now looks something like this:

And with that, the graph is almost finished.

Looking at the viewport with the Voxel Actor, there is definitely a terrain mesh, but it has all sorts of rendering artifacts on it. This is because the mesh does not have any kind of vertex data like Vertex Normals right now, so the engine does not know how to light the terrain.

Going back to the graph, look back to the Create Mesh node. Drag out from its Vertex Data pin and create a Make Vertex Data node. Its vertex colour being black is fine, and its texture coordinates, or UVs, being zero is also fine. The issue is that the terrain normals are not being created. Drag out from the Normal pin, and place a VMGM_GetGradient node.

VMGM_GetGradient is a MetaGraph Macro - read more about macros here: MetaGraph Macros

Now, try to drag from the Density pin into the GetGradient's Value pin. Notice that a pop-up appears, saying Convert Float Buffer (Density) to Float Buffer. Connect the pins, and a new node will appear in between, converting your Density type to a Float type. These nodes are how type conversions appear in MetaGraphs.

Learn more about how float and density types work together on the Floats and Density page.

With all this connected, the graph is now entirely functional and rendering a fully configured mesh.

From here, next steps could be:

  • Material creation, with detail textures for better distant terrain - Passing Data to Materials

  • Using Landmass brushes to modify your terrain manually - Working with Landmass

  • Spawning foliage on your terrain - Getting Started with Foliage

Create Mesh Component takes a Mesh input. Drag out from this pin, and place Create Mesh from Marching Cube Surface. Marching Cubes is the algorithm used to generate smooth terrains from a density field - is good explanation of this topic.

this video
this video by Sebastian Lague
Page cover image