Wormhole / Blackhole

Shader will continuously rotate, churn, pulse, and become more intense when a object enters.

Place a ColorRect or Sprite2D with this canvas_item shader:

 

Shader code
shader_type canvas_item;
render_mode unshaded;


// ----------------------------------------------------
// WORMHOLE SHAPE
// ----------------------------------------------------

uniform float radius : hint_range(0.1, 0.5) = 0.485;
uniform float black_core : hint_range(0.05, 0.45) = 0.19;
uniform float inner_ring : hint_range(0.05, 0.45) = 0.27;

uniform float edge_softness : hint_range(0.001, 0.1) = 0.025;


// ----------------------------------------------------
// ANIMATION
// ----------------------------------------------------

uniform float rotation_speed : hint_range(-5.0, 5.0) = 0.22;
uniform float turbulence_speed : hint_range(0.0, 5.0) = 0.32;
uniform float swirl_strength : hint_range(0.0, 10.0) = 4.2;

uniform float turbulence_scale : hint_range(1.0, 30.0) = 9.0;
uniform float turbulence_amount : hint_range(0.0, 1.0) = 0.62;


// ----------------------------------------------------
// APPEARANCE
// ----------------------------------------------------

uniform vec4 center_color : source_color = vec4(
	0.001,
	0.005,
	0.012,
	1.0
);

uniform vec4 deep_blue : source_color = vec4(
	0.005,
	0.055,
	0.12,
	1.0
);

uniform vec4 blue : source_color = vec4(
	0.0,
	0.28,
	0.58,
	1.0
);

uniform vec4 bright_blue : source_color = vec4(
	0.05,
	0.72,
	1.0,
	1.0
);

uniform vec4 cyan : source_color = vec4(
	0.25,
	0.94,
	1.0,
	1.0
);

uniform float glow_strength : hint_range(0.0, 5.0) = 1.65;
uniform float cloud_brightness : hint_range(0.0, 3.0) = 1.15;


// ----------------------------------------------------
// EXTRA DETAIL
// ----------------------------------------------------

uniform float star_density : hint_range(0.0, 1.0) = 0.12;
uniform float star_brightness : hint_range(0.0, 5.0) = 1.6;

uniform float pulse_strength : hint_range(0.0, 0.5) = 0.055;
uniform float pulse_speed : hint_range(0.0, 10.0) = 1.15;


// ----------------------------------------------------
// GAMEPLAY CONTROL
//
// 0 = idle
// 1 = fully activated / travelling
// ----------------------------------------------------

uniform float activity : hint_range(0.0, 1.0) = 0.0;


// ----------------------------------------------------
// RANDOM / NOISE
// ----------------------------------------------------

float hash21(vec2 p) {
	p = fract(p * vec2(123.34, 456.21));
	p += dot(p, p + 45.32);
	return fract(p.x * p.y);
}


float noise(vec2 p) {
	vec2 i = floor(p);
	vec2 f = fract(p);

	f = f * f * (3.0 - 2.0 * f);

	float a = hash21(i);
	float b = hash21(i + vec2(1.0, 0.0));
	float c = hash21(i + vec2(0.0, 1.0));
	float d = hash21(i + vec2(1.0, 1.0));

	return mix(
		mix(a, b, f.x),
		mix(c, d, f.x),
		f.y
	);
}


float fbm(vec2 p) {
	float value = 0.0;
	float amplitude = 0.5;

	value += noise(p) * amplitude;
	p = p * 2.03 + vec2(17.1, 9.2);
	amplitude *= 0.5;

	value += noise(p) * amplitude;
	p = p * 2.01 + vec2(7.7, 21.6);
	amplitude *= 0.5;

	value += noise(p) * amplitude;
	p = p * 2.04 + vec2(13.5, 4.4);
	amplitude *= 0.5;

	value += noise(p) * amplitude;

	return value;
}


// ----------------------------------------------------
// MAIN
// ----------------------------------------------------

void fragment() {

	// Convert UV to centered coordinates.
	vec2 p = UV - vec2(0.5);

	float dist = length(p);
	float angle = atan(p.y, p.x);

	float t = TIME;


	// ------------------------------------------------
	// Slight breathing / energy pulse
	// ------------------------------------------------

	float pulse =
		sin(t * pulse_speed) *
		pulse_strength *
		(0.35 + activity * 0.65);

	float portal_radius = radius + pulse;


	// ------------------------------------------------
	// Circular mask
	// ------------------------------------------------

	float portal_mask =
		1.0 -
		smoothstep(
			portal_radius - edge_softness,
			portal_radius,
			dist
		);


	// ------------------------------------------------
	// Polar vortex coordinates
	//
	// More rotation toward center creates the spiral.
	// ------------------------------------------------

	float normalized_radius =
		dist / max(portal_radius, 0.001);

	float center_pull =
		1.0 - clamp(normalized_radius, 0.0, 1.0);

	float spiral_angle =
		angle
		+ t * rotation_speed
		+ center_pull * swirl_strength;


	vec2 vortex_uv = vec2(
		cos(spiral_angle),
		sin(spiral_angle)
	);

	vortex_uv *=
		normalized_radius *
		turbulence_scale;


	// Pull the noise around the circle over time.
	vortex_uv += vec2(
		t * turbulence_speed,
		-t * turbulence_speed * 0.47
	);


	// ------------------------------------------------
	// Two turbulence layers
	// ------------------------------------------------

	float n1 = fbm(vortex_uv);

	float n2 = fbm(
		vortex_uv * 1.75
		+ vec2(
			t * -0.18,
			t * 0.27
		)
	);

	float turbulence =
		mix(n1, n2, 0.42);


	// Stronger variation nearer the bright ring.
	float warped_radius =
		normalized_radius
		+ (
			turbulence - 0.5
		) *
		turbulence_amount *
		0.15;


	// ------------------------------------------------
	// BLACK CENTRAL VOID
	// ------------------------------------------------

	float core =
		1.0 -
		smoothstep(
			black_core,
			black_core + 0.15,
			warped_radius
		);


	// ------------------------------------------------
	// INNER BLUE CLOUD
	// ------------------------------------------------

	float cloud_inner =
		smoothstep(
			black_core * 0.65,
			inner_ring,
			warped_radius
		);

	float cloud_outer =
		1.0 -
		smoothstep(
			0.77,
			1.0,
			warped_radius
		);

	float cloud =
		cloud_inner *
		cloud_outer;


	cloud *=
		mix(
			0.35,
			1.25,
			turbulence
		);


	// ------------------------------------------------
	// BRIGHT EVENT-HORIZON STYLE RING
	// ------------------------------------------------

	float ring_center =
		mix(
			0.66,
			0.72,
			turbulence
		);

	float ring_distance =
		abs(
			warped_radius -
			ring_center
		);

	float ring =
		1.0 -
		smoothstep(
			0.015,
			0.105,
			ring_distance
		);


	// Thin hot inner filament.
	float hot_ring =
		1.0 -
		smoothstep(
			0.008,
			0.037,
			abs(warped_radius - 0.67)
		);


	// ------------------------------------------------
	// OUTER BLUE ENERGY
	// ------------------------------------------------

	float outer_energy =
		smoothstep(
			0.68,
			0.84,
			warped_radius
		);

	outer_energy *=
		1.0 -
		smoothstep(
			0.84,
			1.0,
			warped_radius
		);

	outer_energy *=
		0.4 + turbulence * 0.9;


	// ------------------------------------------------
	// STAR / ENERGY PARTICLES
	// ------------------------------------------------

	vec2 star_grid =
		floor(
			vortex_uv * 3.0
		);

	float star_random =
		hash21(star_grid);

	float star =
		step(
			1.0 - star_density,
			star_random
		);

	star *=
		step(
			0.57,
			turbulence
		);

	star *= cloud;

	// flicker
	star *=
		0.45 +
		0.55 *
		sin(
			t * 4.0 +
			star_random * 20.0
		);


	// ------------------------------------------------
	// BUILD COLOR
	// ------------------------------------------------

	vec3 color =
		center_color.rgb;


	// Dark blue around the void.
	color =
		mix(
			color,
			deep_blue.rgb,
			cloud * 0.8
		);


	// Turbulent blue clouds.
	color +=
		blue.rgb *
		cloud *
		turbulence *
		cloud_brightness;


	// Cyan event-horizon ring.
	color +=
		bright_blue.rgb *
		ring *
		glow_strength;


	color +=
		cyan.rgb *
		hot_ring *
		glow_strength *
		0.75;


	// Outer rotating energy.
	color +=
		blue.rgb *
		outer_energy *
		0.85;


	// Small luminous points.
	color +=
		cyan.rgb *
		star *
		star_brightness;


	// Keep center genuinely black.
	color =
		mix(
			color,
			center_color.rgb,
			core * 0.92
		);


	// ------------------------------------------------
	// ACTIVATED STATE
	// ------------------------------------------------

	float activation =
		activity *
		(
			ring * 0.5 +
			outer_energy * 0.4
		);

	color +=
		cyan.rgb *
		activation *
		1.4;


	COLOR = vec4(
		color,
		portal_mask
	);
}
Live Preview
Tags
blackhole, space, Wormhole
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.

Related shaders

guest

0 Comments
Oldest
Newest Most Voted