shader
flakes
(
    float flake_scale = 10.0 [[ string description = "Smaller values zoom into the flake map, larger values zoom out" ]],
    float flake_size = 0.5 [[ string description = "Relative size of the flakes" ]],
    float flake_size_variance = 0.0 [[ string description = "0.0 makes all flakes the same size, 1.0 assigns random size between 0 and the given flake size" ]],
    float flake_normal_orientation = 0.0 [[ string description = "Blend between the flake normals (0.0) and the surface normal (1.0)" ]],
     
    output color result = 1.0,
    output float alpha  = 1.0
)
{
    float safe_flake_size_variance = clamp(flake_size_variance, 0.1, 1.0);
    vector cellCenters[9] = {
        vector( 0.5,  0.5,  0.0),
        vector( 1.5,  0.5,  0.0),
        vector( 1.5,  1.5,  0.0),
        vector( 0.5,  1.5,  0.0),
        vector(-0.5,  1.5,  0.0),
        vector(-0.5,  0.5,  0.0),
        vector(-0.5, -0.5,  0.0),
        vector( 0.5, -0.5,  0.0),
        vector( 1.5, -0.5,  0.0)
    };
     
    point position = vector(u, v, 0.0);
    position = flake_scale * position;
     
    point base = floor(position);
     
    point nearestCell = point(0.0, 0.0, 1.0);
    int nearestCellIndex = -1;
    for(int cellIndex = 0; cellIndex < 9; ++cellIndex)   {
        point cellCenter = base + cellCenters[cellIndex];
         
        vector centerOffset = cellnoise(cellCenter) * 2.0 - 1.0;
        centerOffset[2] *= safe_flake_size_variance;
        centerOffset = normalize(centerOffset);
         
        cellCenter += 0.5 * centerOffset;
        float cellDistance = distance(position, cellCenter);
        if(cellDistance < flake_size && cellCenter[2] < nearestCell[2]) {
            nearestCell = cellCenter;
            nearestCellIndex = cellIndex;
        }
    }
     
    result = color(0.5, 0.5, 1.0);
    alpha = 0.0;
     
    if (nearestCellIndex != -1) {
        vector randomNormal = cellnoise(base + cellCenters[nearestCellIndex] + vector(0.0, 0.0, 1.5));
        randomNormal = 2.0 * randomNormal - 1.0;
        randomNormal = faceforward(randomNormal, I, randomNormal);
        randomNormal = normalize(mix(randomNormal, vector(0.0, 0.0, 1.0), flake_normal_orientation));
         
        result = color(0.5*randomNormal[0]+0.5, 0.5*randomNormal[1]+0.5, randomNormal[2]);
        alpha = 1.0;
    }
}
shader
flakes
(
    float flake_scale = 10.0 [[ string description = "Smaller values zoom into the flake map, larger values zoom out" ]],
    float flake_size = 0.5 [[ string description = "Relative size of the flakes" ]],
    float flake_size_variance = 0.0 [[ string description = "0.0 makes all flakes the same size, 1.0 assigns random size between 0 and the given flake size" ]],
    float flake_normal_orientation = 0.0 [[ string description = "Blend between the flake normals (0.0) and the surface normal (1.0)" ]],
    point proj = point(u, v, 0) [[string label = "Projection"]],
    output color result = 1.0
)
{
    float safe_flake_size_variance = clamp(flake_size_variance, 0.1, 1.0);
    vector cellCenters[9] = {
        vector( 0.5,  0.5,  0.0),
        vector( 1.5,  0.5,  0.0),
        vector( 1.5,  1.5,  0.0),
        vector( 0.5,  1.5,  0.0),
        vector(-0.5,  1.5,  0.0),
        vector(-0.5,  0.5,  0.0),
        vector(-0.5, -0.5,  0.0),
        vector( 0.5, -0.5,  0.0),
        vector( 1.5, -0.5,  0.0)
    };

    //point position = vector(u, v, 0.0);
    point position = flake_scale * proj;

    point base = floor(position);

    point nearestCell = point(0.0, 0.0, 1.0);
    int nearestCellIndex = -1;
    for(int cellIndex = 0; cellIndex < 9; ++cellIndex)   {
        point cellCenter = base + cellCenters[cellIndex];

        vector centerOffset = cellnoise(cellCenter) * 2.0 - 1.0;
        centerOffset[2] *= safe_flake_size_variance;
        centerOffset = normalize(centerOffset);

        cellCenter += 0.5 * centerOffset;
        float cellDistance = distance(position, cellCenter);
        if(cellDistance < flake_size && cellCenter[2] < nearestCell[2]) {
            nearestCell = cellCenter;
            nearestCellIndex = cellIndex;
        }
    }

    result = color(0.5, 0.5, 1.0);

    if (nearestCellIndex != -1) {
        vector randomNormal = cellnoise(base + cellCenters[nearestCellIndex] + vector(0.0, 0.0, 1.5));
        randomNormal = 2.0 * randomNormal - 1.0;
        randomNormal = faceforward(randomNormal, I, randomNormal);
        randomNormal = normalize(mix(randomNormal, vector(0.0, 0.0, 1.0), flake_normal_orientation));

        result = color(0.5*randomNormal[0]+0.5, 0.5*randomNormal[1]+0.5, randomNormal[2]);
    }
}