Performance
This is a list of tips for writing performant noiz code. Always benchmark your noise functions. Small changes can have surprising butterfly affects!
Configuration
Make sure Cargo.toml
is configured for speed.
See this guide for how to do this effectively.
Noiz is so fast because of strongly worded letters to the compiler (#[inline]
) and rust's incredible zero-cost abstractions.
Seriously, noiz is driven by traits and types and it's just as fast as traditional megalithic functions!
Anyway, expect much worse performance when cargo has not been configured to make use of the inlining, etc.
Only Pay for What You Use
Sometimes there's easy ways to make noise algorithms faster:
- Ensure no derivatives are being calculated but those that are needed,
- Consider turning on
Voronoi
's approximation flag, - Switch
Vec3A
forVec3
or visa versa, - Change "libm" backend for "std" or visa versa,
- Try
PerCellPointDistances<Voronoi, EuclideanLength, WorleyDifference>
instead ofDistanceToEdge<Voronoi>
, which give similar results, - Try applying
UNormToSNorm
and similar modifiers afterLayeredNoise
instead of inside it, - Consider trading
RandomElements
forMixCellValuesForDomain
, - Consider using
SelfMasked
instead ofMasked
, - Consider using
Linear
instead ofSmoothstep
, - Consider using
WorleyNearestSmoothMin
instead ofWorleySmoothMin
. - Use
QuickGradients
instead of higher quality but slower generators, - Use
RawNoise
instead ofNoise
to skip scaling, - Use
SampleableFor
andsample_for
instead of their dynamic counterparts when in tight loops for better inlining,
In general, value noise is faster than perlin noise is faster than simplex noise. Sometimes it makes sense to calculate high octaves (that contribute a lot) with simplex or perlin noise, and then calculate details with value or perlin noise. For example:
use noiz::prelude::*;
use bevy_math::prelude::*;
let noise = Noise::<LayeredNoise<
Normed<f32>,
Persistence,
(
FractalLayers<Octave<MixCellGradients<
OrthoGrid,
Smoothstep,
QuickGradients,
>>>,
FractalLayers<Octave<MixCellValues<
OrthoGrid,
Smoothstep,
Random<SNorm, f32>,
>>>,
),
>>::default();
let value: f32 = noise.sample(Vec2::new(1.5, 2.0));
This will generate the large features from perlin noise and use value noise to add some detail on top.
Neat Tricks
If you are filling a volume with data sourced from noise, consider sampling the noise sparsely and interpolating the results. For example, to fill an image, only sample the noise for every other pixel and fill in pixels that weren't filled by noise based on the surrounding filled pixels. This is especially useful for voxel volume generation.