Edit on 2023/04/13: The final version, extended to any dimension, is available in this article.
In a previous article I have introduced a noise generation algorithm based on value noise and Bezier curves. That noise suffered from directional bias, then I've modified it to solve this problem. In the present article I'm introducing a new, directionally unbiased, version of the B-Noise algorithm.
The bias in the previous version came from the choice of using two Bezier curves per axis, each using one axis as input. For a given value in one axis, one of the curve for each axis will have a fixed value whatever the value of the other axis. It creates a fixed point aligned with the axes, hence with the underlying grid, which the funtion \(F()\) fails to hide. Choosing two Bezier surfaces instead, one per mapped coordinate, these coordinates vary with both input coordinates. This decorrelates completely the inputs and the underlying grid, avoiding directional bias. Of course, the new version is still continuous, differentiable, tilable. It also stays simple to implement, and efficient to compute.
The pseudo-code becomes:
Edit on 2023/04/03: Note that the output value range for one instance of B-Noise generally won't cover the whole [0,1] range. This range is included in the grid values range, these values being picked at random they will most often not contain 0 and 1, hence their range, and consequently the one of the output, will be smaller than [0,1]. The lower the order of the noise, the higher the probablity for a small range of output values. If this is a concern for the user, normalising the grid values right after their initialisation will almost solve the problem. Only 'almost' because the values in the grid are interpolated at positions generated by the Bezier surfaces, and these positions are not guaranteed to cover the whole grid. That would probably be good enough for artistic purposes.
The examples below show the new results. We can clearly see that the directional bias has disappeared.
And finally, the implementation in C. Header file:
Edit on 2023/04/06: Correction of a bug in the C implementation. Initialisation of center handles used round(rng() * (float)order) instead of rng() * (float)order.