Volumetric Cosmic Dust

This is an advanced, procedural shader system adapted for Godot’s CanvasItem that generates a dynamic, rotating spiral galaxy. The effect relies on complex trigonometric transformations and multi-octave noise (Fractal Brownian Motion or FBM) to simulate the characteristic structure of stellar arms and dense cosmic dust clouds.

The shader works by:

  1. Transforming Coordinates: Applying shear and logarithmic spiral functions to map UV coordinates into a spiral space.

  2. Generating Dust: Using a turbulent noise function (FBM based on multiple noise octaves) to create realistic dust clouds, with intensity controlled by dust_strength.

  3. Rendering Volumetrics: Applying density masks (disk_density) to blend the dust, core, and background colors, giving the galaxy a deep, volumetric appearance.

The original concept for this kind of galaxy generation often stems from mathematical models and general noise techniques (like those popularized by Inigo Quilez).

 

Adjustable Uniforms (Shader Parameters):

 

Parameter Type Controls Description
dust_strength float Dust appearance Controls the contrast and sharpness of the dust clouds (higher = sharper).
dust_color `vec3** Dust color The primary color of the dense dust lanes and arms.
arm_count float Spiral structure Sets the number of major spiral arms (e.g., 2, 3, or 5).
arm_compression float Arm shape Controls how tightly compressed the spiral arms are against the main disk.
core_radius float Core size Determines the size and intensity of the central stellar bulge/glow.
core_color `vec3** Core color The color of the central glow of the galaxy’s core.
galaxy_radius float Disk size The overall spatial extent of the galaxy’s main disk.
rotation_speed float Animation Controls the speed at which the spiral arms and dust clouds rotate.
sky_color `vec3** Background The color of the deep space surrounding the galaxy.
star_size float Star field Controls the scale of the noise used to render the background star field.
galaxy_center vec2 Position Allows for shifting the center point of the galaxy on the screen (normalized UV).
noise_texture_1/2 sampler2D Required Input These must be assigned Noise Textures (e.g., Godot’s FastNoiseLite) to provide the random data necessary for FBM generation and the star field.
Shader code
shader_type canvas_item;

uniform float dust_strength : hint_range(0.0, 5.0) = 3.0;
uniform vec3 dust_color : source_color = vec3(0.8, 0.34, .43);
uniform float arm_count : hint_range(0.0, 10.0) = 5.0;
uniform float arm_compression : hint_range(0.0, 1.0) = 0.1;
uniform float core_radius : hint_range(0.0, 1.0) = 0.25;
uniform vec3 core_color : source_color = vec3(.98, 0.8, 0.79);
uniform float galaxy_radius : hint_range(0.1, 2.0) = 0.5;
uniform float rotation_speed : hint_range(0.0, 1.0) = 0.1;
uniform vec3 sky_color : source_color = vec3(0.23, 0.08, 0.14);
uniform float star_size : hint_range(0.1, 2.0) = 0.537;
uniform vec2 galaxy_center = vec2(0.5, 0.5);

uniform sampler2D noise_texture_1;
uniform sampler2D noise_texture_2;

float get_noise_value(vec2 uv) {
	float n = texture(noise_texture_1, uv).r;
	return 1.0 - abs(2.0 * n - 1.0);
}

float turbulent_noise(vec2 uv) {
	float value = 0.0;
	float angle = -rotation_speed * TIME;
	mat2 rotation_matrix = mat2(vec2(cos(angle), -sin(angle)), vec2(sin(angle), cos(angle)));
	
	float scale = 1.0;
	for (int i = 0; i < 7; i++) {
		uv = rotation_matrix * uv;
		float noise_val = get_noise_value(uv * scale);
		value += (1.0 / scale) * pow(noise_val, dust_strength);
		scale *= 2.0;
	}
	
	return value / 2.0;
}


void fragment() {
	vec2 uv = UV - galaxy_center;
	
	float aspect_ratio = (1.0 / SCREEN_PIXEL_SIZE).x / (1.0 / SCREEN_PIXEL_SIZE).y;
	uv.x *= aspect_ratio;
	float rho = length(uv);
	float ang = atan(uv.y, uv.x);
	float shear = 2.0 * log(rho);
	mat2 shear_matrix = mat2(vec2(cos(shear), -sin(shear)), vec2(sin(shear), cos(shear)));

	float disk_density = exp(-pow(rho / galaxy_radius, 2.0));
	float core_glow = exp(-pow(rho / core_radius, 2.0));
	
	float phase = arm_count * (ang - shear);
	float arm_warp_angle = ang - arm_compression * cos(phase) + rotation_speed * TIME;
	vec2 warped_uv = rho * vec2(cos(arm_warp_angle), sin(arm_warp_angle));
	
	float arm_density = 1.0 + arm_count * arm_compression * sin(phase);
	disk_density *= 0.7 * arm_density;	
	
	float dust = turbulent_noise(0.09 * 1.2 * shear_matrix * warped_uv);
	float dust_transparency = pow((1.0 - dust * disk_density), 2.0);

	float stars1 = texture(noise_texture_2, star_size * uv + 0.5).r;
	float stars2 = texture(noise_texture_1, star_size * uv + 0.5).r;
	float stars = pow(1.0 - (1.0 - stars1) * (1.0 - stars2), 5.0);
	
	vec3 final_color;
	final_color = mix(sky_color, dust_transparency * (1.7 * dust_color) + 1.2 * stars, disk_density);
	final_color = mix(final_color, 1.2 * core_color, core_glow);
		
	COLOR = vec4(final_color, 1.0);
}
Tags
Abstract, Astronomy, Cosmos, fbm, galaxy, godotshader, noise, Procedural, space, spiral, volumetric
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from Gerardo LCDF

Reflective Crystalline Voronoi

Snake Game

Fractal Rotation Sphere

Related shaders

Volumetric Raymarched (animated) Clouds v2

Volumetric nebulae/clouds

Volumetric Billboards (3D Texture sampled by plane stacking)

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments