Voronoi shader with different distance metrics

I redid an earlier implementation of my OSL Voronoi shader because the Cycles Voronoi shader does not support any other distance metric than distance squared. The details with an example and a pointer to the code is in this article. I hardly had to code any anything as most code is already distributed with Blender (just with the different metrics commented out!)

Some examples:






(distance metrics used were manhattan, chebyshev and minkovsky 4 respectively)

Cheers,

– Michel.

Thought I’d give this a whirl for a scaly skin texture. Kind of neat.


I added an interesting distance ‘metric’ to the basic voronoi node. Detail here, some examples:

[ATTACH=CONFIG]394889[/ATTACH][ATTACH=CONFIG]394890[/ATTACH][ATTACH=CONFIG]394891[/ATTACH]

I am also working on extending the built-in cycles voronoi node with a metric selection and a F2 output in order enjoy full speed on a GPU. The patch is currently under review.

I did a voronoi shader with nodes a few months ago, but my working pc broke down at the time and my laptop simply can’t even compile the shader, so it means I never tried it.
It is suposed to return the [F1,F4] values which can be usefull for a variety of effects.
But here’s the file just for fun: voronoi_extended_GPU.blend (572 KB)

@Secrop: as far as I can see there is no voronoi material in the .blend…

It’s not a material, just a node group.
And i don’t know if there’s a better way to sort the distances… If it was just find F1, than every ‘sorter’ node could be replaced with a few minimum nodes, but for F2 and further gets complex pretty fast.

@Secrop: I see it now, didn’t look into the groups :frowning:

Like you said, without loops or variables the complexity just explodes. You probably could use your sorter group to create a complete sorting network (F1 would then come out of top, F2 would the 2nd one etc. This isn’t necessarily more complex than just finding F1)
but a full implementation might not fit the stack (I think with 27 random neighbouring points you need at least a noise node and a vector add node per point plus the nodes to calculate the distance (vector subtract plus dot) that’s 112 nodes already plus the sorting network. the last one needs (27 ^2)/2 comparison groups of two nodes each) which is over 800 nodes. (the sorting network can probably made a little bit more efficient but this gives an idea)

That simply won’t fit. That’s why I try to convince the Blender devs to include my patch (or a simpler variant) :slight_smile:

PS> and with that many groups even when running on the GPU it might not even be faster than OSl on the CPU

I’ve looked into the code for this myself and one thing struck me a while back when I tried to do the classic skin/cracked mud type effect. In nature the basis is not square as is used by most voronoi implementations but more hexagonal. So I duly made an attempt at a hexagonal based voronoi. It’s not perfect, definitely a work in progress and could do with some optimisation but some critique may help. Or alternatively rip it off :slight_smile:
Fac by the way controls the amount of distortion from a hexagon.

Apologies for the formatting. I’m somewhat new to this forum and posting isn’t my strongpoint.

#define H 0.86602540378443864676372317075294 // sqrt(3)/2
#define H2 (2 * H)
#define H3 (3 * H)
#define H4 (4 * H)
#define H5 (5 * H)
#define H6 (6 * H)
#define HY (1 / H)
#define HY8 (.5 / H4)

#define HL 7

void genHexPoints(vector pp, vector h[]) {
int i;

vector hh[HL] = {
    vector(1.5, H2, 0),    // Center Point
    vector(0, H, 0),
    vector(1.5, 0, 0),    
    vector(0, H3, 0),
    vector(1.5, H4, 0),    
    vector(3, H, 0),
    vector(3, H3, 0)
};
for (i = 0; i < HL; i++) {
    h[i] = pp + hh[i];
}

}

shader hexapoints(
vector Pos = 0,
float Scale = 5,
float Fac = 1,
output float Dist = 0,
output float Bord = 0,
output float BordNm = 0,
output color Col = color(0,0,0))
{
// This centers 1 hexagon in the range 0 - 1 x, y
vector p = vector(abs(Pos[0]) * 2 * Scale + 2, abs(Pos[1]) * 2 * Scale - HY8 + H2, 0);

// calculate the origin point of the hexagon array
// float sx = mod(p[0], 3);    float sy = mod(p[1], H4); float sz = mod(p[2], H4);
vector pp = vector(p[0] - mod(p[0], 3), p[1] - mod(p[1], H4), 0);

float d, cd = 1000, bd = 1000;
color c, cl;
vector cn, bp, cp, h[HL], f = vector(Fac * .75, Fac * H, 1);
int i, j = 0, k = 3;


do {
    genHexPoints(pp , h);    
    for (i = 0; i < HL; i++) {
        cn = vector(cellnoise(h[i][0], h[i][1]), cellnoise(h[i][1], h[i][0]), .5);
        d = distance(p, (cn - .5) * f + h[i]);
        if (d <= cd) {
            cp = h[i];
            j = i;
            cd = d;
        } else if (d <= bd) {
            bp = h[i];
            bd = d;
        }
    }
    if (j) {
        pp = h[j] - vector(1.5, H2, 0);
        //bd = 1000;
    }
} while(j && --k);


c = color(cellnoise(cp[0], cp[1]), cellnoise(cp[1], cp[0]), cellnoise(cellnoise(cp[0], cp[1]) * 1000, cellnoise(cp[1], cp[0]) * 1000));
Dist =  cd;
Bord = bd - cd;
BordNm = 1 - (2 * cd) / (bd + cd);
Col = c;

}

enjoy…