# How does Smooth F1 Voronoi work mathematically?

I’m told that Smooth F1 Voronoi uses Smooth Minimum to visually smooth out the Voronoi Edges.
But how does it do that? I know the math behind Smooth Minimum and F1 Worley Noise, but how does Smooth Minimum selectively choose the Voronoi Edges as sharp corners to be smoothed out instead of the top or bottom of the displaced Voronoi Diagram?

(F1 Worley Noise)

(F1 Worley Noise with separate Minimum node applied)

(F1 Worley Noise with separate Smooth Minimum node applied)

(Smooth F1 Worley Noise)

You can see that the separate Minimum function slices the top of the displaced Voronoi Diagram, but to make that slice looks more organic, we can use Smooth Minimum (smin) instead of Minimum (min).
smin literally does the same job as min, it also visually smooth out the sharp corners generated by min.

So, Smooth F1 Voronoi is different to the combination F1 Voronoi + Smooth Minimum. Please help me understand what the math behind Smooth F1 Voronoi is. Also, what is “Smoothness” input? Is it the same as parameter “Distance” of Smooth Minimum?
Thank you!

1 Like

Can you read C++ code? If yes, the fasted way to find out is to look at the Blender code itself:

If not, then my apologies, my math isn’t up to explaining that. Hopefully somebody else will be able to.

2 Likes

Thank you. I’m a math student, not a programmer so unfortunately I can’t read codes. I’ve been asking around though but programmers can’t seem to help.

You may find something useful here (also have a look at the links in the code):

Especially this part:

``````void voronoi_smooth_f1(const float w,
const float smoothness,
const float randomness,
float *r_distance,
float3 *r_color,
float *r_w)
{
const float cellPosition = floorf(w);
const float localPosition = w - cellPosition;
const float smoothness_clamped = max_ff(smoothness, FLT_MIN);

float smoothDistance = 8.0f;
float smoothPosition = 0.0f;
float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
for (int i = -2; i <= 2; i++) {
const float cellOffset = i;
const float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * randomness;
const float distanceToPoint = voronoi_distance(pointPosition, localPosition);
const float h = smoothstep(
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness_clamped);
float correctionFactor = smoothness * h * (1.0f - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
if (r_color != nullptr || r_w != nullptr) {
correctionFactor /= 1.0f + 3.0f * smoothness;
if (r_color != nullptr) {
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
}
if (r_w != nullptr) {
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
}
}
if (r_distance != nullptr) {
*r_distance = smoothDistance;
}
if (r_color != nullptr) {
*r_color = smoothColor;
}
if (r_w != nullptr) {
*r_w = cellPosition + smoothPosition;
}
}
``````

To calculate the value of a pixel, it seems to consider a 5x5 pixel neighborhood.

As far as I can see, the part of the code that is closest to what you are looking for. Each part should have a clear definition that you can look up.

1 Like

Thank you so much.

Really appreciate you searching for the code. But to be honest, I fail to understand the code at all. Reading the code is easy to you but not to non-programmers.

I think an intuition should be fine for me. Someone told the the intuition of Smooth F1 Worley Noise is that it uses Smooth Minimum function smin(d₁,d₂,d₃,…) instead of Minimum function min(d₁,d₂,d₃,…) like the original Worley Noise. Would this be correct?
While that’s the intuition, they told me the Blender’s implemented Smooth F1 Worley Noise actually implemented SmoothStep Interpolation instead of Smooth Minimum. Though, theoretically, should the intuition and the code produce the same thing?

Did you have a look at the links in the code?

This one might be most interesting:
https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi

1 Like

Thank you. Yes I have!
It introduces Voronoi Diagram and Smooth Minimum separately but doesn’t explain how Smooth Minimum is used to create Smooth F1 Voronoi.
I know both Voronoi Diagram and Smooth Minimum and can derive them, but I have no idea how Smooth F1 Voronoi is created.

To get the result for one pixel, it computes the voronoi distances of all its 5x5 neighboring pixels and computes weights for them in a fancy way to mix them. This might be the smooth minimum, but I am really not sure. (To understand it better, I would need to invest a lot of time.)

1 Like

Thank you. I’ll keep asking around and hope for the best.

By the way, did you mean 5x5 neighboring Voronoi Seeds (Feature Points) instead of 5x5 neighboring pixels? As far as I know, in Worley Noise, a point (pixel) is evaluated based on its distance to the nearest Voronoi Seed, not nearest pixel.

I think you are right. And it it is not 5x5, but just 5.

1 Like