# How to generate chaotic halftone pattern?

I'm trying to generate a random halftone like below image:

this is a simple halftone that I tried, but I need a random halftone

float PI = 3.14159265359;

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 p = (fragCoord.xy / iResolution.xy - 0.5)/0.5;

vec3 n = vec3(p, sqrt(dot(p, p)));
vec2 s = vec2(acos(n.z), atan(n.y, n.x))/PI;
vec2 uv = fract(s * vec2(30.0, 30.0));
float r = ceil(s.x * 30.0) / 17.0;
fragColor =  vec4(1.)*step(length(uv - 0.5),r);
}


I also tried using for-loop and sin,cos, but I need a low computing method because I want generate it in the game engine.

• Where did you find the above image? Jan 5, 2018 at 7:05
• @user1118321 google search :) Jan 5, 2018 at 8:59
• Did the page it came from have any information about it? Just curious because sometimes the artist will discuss how they created it. I have an idea of one way it might work, but am not sure how close it would be. Jan 5, 2018 at 16:54
• @user1118321 feel free tell me your solution Jan 5, 2018 at 17:00
• I'm looking some stuff up about it and will write something when I've got something concrete. Jan 5, 2018 at 19:35

I could make it by Worley noise

Worley noise is a noise function introduced by Steven Worley in 1996. In computer graphics it is used to create procedural textures,that is textures that are created automatically in arbitrary precision and don't have to be drawn by hand. Worley noise comes close to simulating textures of stone, water, or cell noise.

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

// Permutation polynomial: (34x^2 + x) mod 289
vec4 permute(vec4 x) {
return mod((34.0 * x + 1.0) * x, 289.0);
}
vec3 permute(vec3 x) {
return mod((34.0 * x + 1.0) * x, 289.0);
}

// Cellular noise, returning F1 and F2 in a vec2.
// Speeded up by using 2x2x2 search window instead of 3x3x3,
// at the expense of some pattern artifacts.
// F2 is often wrong and has sharp discontinuities.
// If you need a good F2, use the slower 3x3x3 version.
vec2 cellular2x2x2(vec3 P) {
#define K 0.142857142857 // 1/7
#define Ko 0.428571428571 // 1/2-K/2
#define K2 0.020408163265306 // 1/(7*7)
#define Kz 0.166666666667 // 1/6
#define Kzo 0.416666666667 // 1/2-1/6*2
#define jitter 0.8 // smaller jitter gives less errors in F2
vec3 Pi = mod(floor(P), 289.0);
vec3 Pf = fract(P);
vec4 Pfx = Pf.x + vec4(0.0, -1.0, 0.0, -1.0);
vec4 Pfy = Pf.y + vec4(0.0, 0.0, -1.0, -1.0);
vec4 p = permute(Pi.x + vec4(0.0, 1.0, 0.0, 1.0));
p = permute(p + Pi.y + vec4(0.0, 0.0, 1.0, 1.0));
vec4 p1 = permute(p + Pi.z); // z+0
vec4 p2 = permute(p + Pi.z + vec4(1.0)); // z+1
vec4 ox1 = fract(p1*K) - Ko;
vec4 oy1 = mod(floor(p1*K), 7.0)*K - Ko;
vec4 oz1 = floor(p1*K2)*Kz - Kzo; // p1 < 289 guaranteed
vec4 ox2 = fract(p2*K) - Ko;
vec4 oy2 = mod(floor(p2*K), 7.0)*K - Ko;
vec4 oz2 = floor(p2*K2)*Kz - Kzo;
vec4 dx1 = Pfx + jitter*ox1;
vec4 dy1 = Pfy + jitter*oy1;
vec4 dz1 = Pf.z + jitter*oz1;
vec4 dx2 = Pfx + jitter*ox2;
vec4 dy2 = Pfy + jitter*oy2;
vec4 dz2 = Pf.z - 1.0 + jitter*oz2;
vec4 d1 = dx1 * dx1 + dy1 * dy1 + dz1 * dz1; // z+0
vec4 d2 = dx2 * dx2 + dy2 * dy2 + dz2 * dz2; // z+1

// Sort out the two smallest distances (F1, F2)
#if 0
// Cheat and sort out only F1
d1 = min(d1, d2);
d1.xy = min(d1.xy, d1.wz);
d1.x = min(d1.x, d1.y);
return sqrt(d1.xx);
#else
// Do it right and sort out both F1 and F2
vec4 d = min(d1,d2); // F1 is now in d
d2 = max(d1,d2); // Make sure we keep all candidates for F2
d.xy = (d.x < d.y) ? d.xy : d.yx; // Swap smallest to d.x
d.xz = (d.x < d.z) ? d.xz : d.zx;
d.xw = (d.x < d.w) ? d.xw : d.wx; // F1 is now in d.x
d.yzw = min(d.yzw, d2.yzw); // F2 now not in d2.yzw
d.y = min(d.y, d.z); // nor in d.z
d.y = min(d.y, d.w); // nor in d.w
d.y = min(d.y, d2.x); // F2 is now in d.y
return sqrt(d.xy); // F1 and F2
#endif
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ){

vec2 uv = (fragCoord.xy - iResolution.xy*.5)/iResolution.y;

float w = 1. - dot(uv, uv)*3.;

uv *= 48.;
vec2 ip = floor(uv);
vec2 v = cellular2x2x2(vec3(uv, iTime/2.));

float c = v.x; //v.y - v.x

c -= .35*w;

c = smoothstep(0., max(.1/c, 0.), c);

vec3 col = mix(vec3(0), vec3(1), c);

fragColor = vec4(sqrt(max(col, 0.)), 1);
}


Years ago, Pete Warden wrote either a blog post or perhaps it was an entry in one of the GPGPU Gems books where he described how to generate similar patterns. I believe that when he was at Apple, he implemented this as the "Cellular" generator in Motion. It looks like this:

I'm unable to find the original blog post or whatever it was, but if I recall correctly, it was generated like this:

1. Generate a list of random locations for the "cells"
2. At each cell's location, draw a small circle where:

2.1. the depth at each pixel is the inverse of the distance to the center (so highest at the center, and lowest at the edges)

2.2. the color is a radial gradient (in this case black at the center, white at the edges)

I think if you further modified this algorithm to make the radius of each cell be related to the luminance of an input image at its location or make its color lighter for higher luminance positions, you could get such a half-tone look.

• thanks good explanation but I need your help to implementing this. I tried cellular noise see this shader if you help me I accept your question :) Jan 6, 2018 at 4:47