Highly customisable moving voronoi diagram transition

Use on a CanvasItem

Features:

  • Can be used as a transition effect, changing the circles radii
  • Turn on/off center visualization
  • Turn on/off movement
  • Visualize borders
  • Use of Minkowski distance
Shader code
shader_type canvas_item;

uniform float radius : hint_range(0.0, 1.0, 0.01) = 0.45;
uniform int center_number : hint_range(1, 1024, 1)  = 100;
uniform sampler2D circle_color_gradient; // GradientTexture2D
uniform float seed : hint_range(0.0, 1.0, 0.01) = 0.0;
uniform bool draw_centers = false;
uniform bool draw_borders = false;
uniform vec4 border_color : source_color = vec4(vec3(0.0),1.0);
uniform float center_radius : hint_range(0.0, 1.0, 0.001)= 0.005;
uniform sampler2D center_color_gradient;
uniform bool move = true;
uniform float speed : hint_range(0.0, 1.0, 0.001)= 0.02;
uniform float outline_thickness_mult = 1.5;
uniform float minimum_thickness : hint_range(0.0, 0.01, 0.0001) = 0.0; 
uniform vec4 background_color : source_color = vec4(0.0); // only visible with small circles
uniform float minkowski_distance_p = 2.0;

// generic random function
float random(vec2 uv) {
	return fract(sin(dot(uv, vec2(12.9898, 78.233)) + seed) * 43758.5453);
}

float minkowski_distance(vec2 p1, vec2 p2, float p){
	return pow(pow(abs(p1.x-p2.x),p) + pow(abs(p1.y-p2.y),p), 1.0/p);
}

void fragment() {
	vec2 uv = UV;
	vec2 deriv = fwidthFine(uv); // not available with compatibility renderer
	float aspect_ratio = deriv.y / deriv.x;
	uv.x *= aspect_ratio;

	float best_dist = 1e9;
	float second_best_dist = 1e9;
	vec2 best_center = vec2(0.0);
	
	// my GPU hates me
	for (int i = 0; i < center_number; i++) {
		float fi = float(i);
		vec2 base = vec2(random(vec2(fi, 0.0)), random(vec2(fi, 1.0))); // random coord for center of circle
		vec2 raw;

		if (move) {
			float angle = random(vec2(fi, 2.0)) * TAU; // random angle for movement in radians
			raw = base + vec2(cos(angle), sin(angle)) * (speed * TIME);
			raw = fract(raw);
		} else {
			raw = base;
		}
		// Every circle also has "copies" at every integer offset.
		// We only need offsets for -1, 0, +1 in x and y (the 3×3 block)
		// because circles in further offsets will never be shown.

		for (int xi = -1; xi <= 1; xi++) {
			for (int yi = -1; yi <= 1; yi++) {
				// get shifted center
				vec2 candidate = raw + vec2(float(xi), float(yi));
				candidate.x *= aspect_ratio;
				float d = minkowski_distance(uv, candidate,minkowski_distance_p);
				if (d < best_dist) {
					second_best_dist = best_dist;
					best_dist = d;
					best_center = candidate;
				}else if (d < second_best_dist) {
				    second_best_dist = d;
				}
			}
		}
	}

	if (best_dist < radius) {
		vec4 color;
		vec2 best_center_corrected = vec2(best_center.x / aspect_ratio, best_center.y);
		vec2 uv_corrected = vec2(uv.x / aspect_ratio, uv.y);
		// paint pixel according to the color of the closest center
		COLOR = texture(circle_color_gradient,best_center_corrected);
		if (draw_borders) {
			float d = second_best_dist - best_dist;
			float edge_thickness = fwidth(d) * outline_thickness_mult  + minimum_thickness;
			if (d < edge_thickness) {
				COLOR = border_color;
			}
		}

		if (draw_centers && best_dist < center_radius) {
			COLOR = texture(center_color_gradient, vec2(uv.x / aspect_ratio, uv.y));
		}

	} else {
		COLOR = background_color;
	}
}
Tags
background, transition, voronoi
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from HalconVengador

Moving circles effect background

Markers or Pins

Related shaders

Highly customizable circle

Combustible Voronoi

Voronoi Synapse-ish Background Shader

guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
B K
B K
2 months ago

Fantastic! Works great!