pub fn uniform_noise<F: Float + Send>(
    map_size_lg: MapSizeLg,
    f: impl Fn(usize, Vec2<f64>) -> Option<F> + Sync
) -> (Box<[(f32, F)]>, Box<[(usize, F)]>)
Expand description

Compute inverse cumulative distribution function for arbitrary function f, the hard way. We pre-generate noise values prior to worldgen, then sort them in order to determine the correct position in the sorted order. That lets us use (index + 1) / (WORLDSIZE.y * WORLDSIZE.x) as a uniformly distributed (from almost-0 to 1) regularization of the chunks. That is, if we apply the computed “function” F⁻¹(x, y) to (x, y) and get out p, it means that approximately (100 * p)% of chunks have a lower value for F⁻¹ than p. The main purpose of doing this is to make sure we are using the entire range we want, and to allow us to apply the numerous results about distributions on uniform functions to the procedural noise we generate, which lets us much more reliably control the number of features in the world while still letting us play with the shape of those features, without having arbitrary cutoff points / discontinuities (which tend to produce ugly-looking / unnatural terrain).

As a concrete example, before doing this it was very hard to tweak humidity so that either most of the world wasn’t dry, or most of it wasn’t wet, by combining the billow noise function and the computed altitude. This is because the billow noise function has a very unusual distribution that is heavily skewed towards 0. By correcting for this tendency, we can start with uniformly distributed billow noise and altitudes and combine them to get uniformly distributed humidity, while still preserving the existing shapes that the billow noise and altitude functions produce.

f takes an index, which represents the index corresponding to this chunk in any any SimChunk vector returned by uniform_noise, and (for convenience) the float-translated version of those coordinates. f should return a value with no NaNs. If there is a NaN, it will panic. There are no other conditions on f. If f returns None, the value will be set to NaN, and will be ignored for the purposes of computing the uniform range.

Returns a vec of (f32, f32) pairs consisting of the percentage of chunks with a value lower than this one, and the actual noise value (we don’t need to cache it, but it makes ensuring that subsequent code that needs the noise value actually uses the same one we were using here easier). Also returns the “inverted index” pointing from a position to a noise.