-
-
Notifications
You must be signed in to change notification settings - Fork 144
Getting started using FastNoise2
This guide covers the fundamentals of using FastNoise2 in your C++ code. Make sure you have already included the library in your project setup.
All you need is a single include:
#include <FastNoise/FastNoise.h>This gives you access to all node types, SmartNode, and the generation functions.
Nodes are created with FastNoise::New<T>() which returns a SmartNode<T> - a reference-counted smart pointer that manages the node's lifetime automatically.
auto simplex = FastNoise::New<FastNoise::Simplex>();Nodes cannot be copied or moved directly. Always work with them through SmartNode.
FastNoise2 uses a node graph architecture where you connect nodes together to build complex noise. A simple example is wrapping a noise generator in a fractal:
// Create the base noise generator
auto simplex = FastNoise::New<FastNoise::Simplex>();
// Create a fractal and connect the simplex as its source
auto fractal = FastNoise::New<FastNoise::FractalFBm>();
fractal->SetSource( simplex );
fractal->SetOctaveCount( 5 );You can build arbitrarily complex trees by chaining nodes:
// Simplex noise -> FBm fractal -> domain warp
auto simplex = FastNoise::New<FastNoise::Simplex>();
auto fractal = FastNoise::New<FastNoise::FractalFBm>();
fractal->SetSource( simplex );
fractal->SetOctaveCount( 4 );
auto warp = FastNoise::New<FastNoise::DomainWarpGradient>();
warp->SetSource( fractal );
warp->SetWarpAmplitude( 50.0f );Make sure all sources are set for a node before generating any noise, failure to do so will cause a nullptr access crash. This is only an issue when creating node trees in code, the Node Editor cannot export an invalid node tree
Always call the generation function on the root (outermost) node of your tree. In the example above, that's warp, not simplex.
Ideal for generating noise for 2D textures, heightmaps, or image buffers that require uniform spacing between sample positions:
const int width = 256;
const int height = 256;
std::vector<float> noiseData( width * height );
auto minMax = generator->GenUniformGrid2D(
noiseData.data(),
0.0f, 0.0f, // xOffset, yOffset - starting position in world space
width, height, // xCount, yCount - number of samples per axis
1.0f, 1.0f, // xStepSize, yStepSize - distance between samples
1337 // seed
);
// minMax.min and minMax.max tell you the range of generated values
// Output is in row-major order: noiseData[y * width + x]Step size controls how zoomed in the noise is. Smaller values (e.g. 0.5) zoom in, larger values (e.g. 2.0) zoom out. This is independent of the node's Feature Scale setting.
For volumetric data like voxel terrain or 3D textures:
const int sizeX = 64, sizeY = 64, sizeZ = 64;
std::vector<float> noiseData( sizeX * sizeY * sizeZ );
generator->GenUniformGrid3D(
noiseData.data(),
0.0f, 0.0f, 0.0f, // starting position in world space
sizeX, sizeY, sizeZ, // sample counts
1.0f, 1.0f, 1.0f, // step sizes
1337 // seed
);
// Output order: noiseData[(z * sizeY + y) * sizeX + x]Performance tip: Avoid setting xCount = 1 when you want a 2D slice of 3D noise. Due to how positions are generated internally, a small xCount is bad for performance. Use yCount = 1 or zCount = 1 instead to get a slice.
For textures that need to tile seamlessly:
const int tileSize = 256;
std::vector<float> noiseData( tileSize * tileSize );
generator->GenTileable2D(
noiseData.data(),
tileSize, tileSize, // tile dimensions
1.0f, 1.0f, // step sizes
1337 // seed
);Note: Tileable generation works by mapping onto 4D coordinates internally, so the underlying noise types will be using 4D generation.
Can be used for sampling at non-uniform positions (mesh vertices, particle positions, etc.):
GenPositionArray is actually faster than GenUniformGrid because the uniform grid positions don't need to be generated each call. For maximum generation performance across many calls, pre-generate your own position arrays once and reuse them, using the offset parameters to shift the sampling region:
// Pre-generate positions once
std::vector<float> xPositions( 256 * 256 );
std::vector<float> yPositions( 256 * 256 );
for( int y = 0; y < 256; y++ )
for( int x = 0; x < 256; x++ )
{
xPositions[y * 256 + x] = (float)x;
yPositions[y * 256 + x] = (float)y;
}
// Reuse positions for each generation call, shifting with offsets
std::vector<float> noiseData( 256 * 256 );
generator->GenPositionArray2D(
noiseData.data(),
(int)xPositions.size(),
xPositions.data(), yPositions.data(),
chunkX, chunkY, // offsets shift positions without modifying the arrays
1337 // seed
);GenSingle is significantly slower per-sample than the batch methods because SIMD lanes are underutilised. Avoid using it unless you truly only need a single sample:
float value = generator->GenSingle2D( 10.5f, 20.3f, 1337 );Do not use GenSingle in a loop. If you need multiple values, use GenPositionArray or GenUniformGrid instead.
The Node Editor lets you visually create node trees and export them as encoded strings. To load one:
auto generator = FastNoise::NewFromEncodedNodeTree( "DQkGDA==" );
if( generator )
{
std::vector<float> noise( 256 * 256 );
generator->GenUniformGrid2D( noise.data(), 0, 0, 256, 256, 1, 1, 1337 );
}To get an encoded string from the Node Editor, right-click a node title and select Copy Encoded Node Tree.
This workflow is ideal for rapid iteration: tweak in the Node Editor, copy the string, paste into code.
Every noise generator that inherits from ScalableGenerator has a Feature Scale parameter (set via SetScale()). This controls the size of noise features in world units:
-
SetScale(100)- Each noise feature spans roughly 100 world units (default) -
SetScale(50)- Features are half the size, more detailed -
SetScale(200)- Features are twice as large, smoother
Feature Scale is the inverse of frequency: frequency = 1.0 / scale. If you're used to working with frequency, simply use SetScale(1.0f / yourFrequency).
This is separate from the step size in generation functions. Step size controls the sampling density, while Feature Scale controls the noise pattern itself.
Seeds determine the random pattern of the noise. The same seed always produces the same output for the same position.
auto simplex = FastNoise::New<FastNoise::Simplex>();
// These produce different patterns:
simplex->GenSingle2D( 0, 0, 1337 ); // seed 1337
simplex->GenSingle2D( 0, 0, 42 ); // seed 42Nodes that inherit from Seeded also have a Seed Offset (SetSeedOffset()), which is added to the generation seed for that node only. This is useful when you have multiple nodes of the same type and want different outputs without changing the global seed:
auto noise1 = FastNoise::New<FastNoise::Simplex>();
auto noise2 = FastNoise::New<FastNoise::Simplex>();
noise2->SetSeedOffset( 1 ); // now noise2 produces a different pattern from noise1All generation methods (GenUniformGrid*, GenPositionArray*, GenSingle*, GenTileable2D) are const and fully thread-safe. You can safely share a single node tree across multiple threads and call generation methods concurrently.
auto generator = FastNoise::New<FastNoise::Simplex>();
// Safe to do from multiple threads simultaneously:
// Thread 1: generator->GenUniformGrid2D( ... );
// Thread 2: generator->GenUniformGrid2D( ... );However, do not modify node parameters (e.g. SetSource, SetScale) while generation is in progress on another thread.
- Understanding Noise Types - Learn how different noise algorithms work
- Node Graph Architecture - Understand why nodes and how to compose them
- Node Reference pages - Detailed docs for every node type and parameter
- FAQ - Common questions and troubleshooting