Aurora Borealis

A shader that combines raymarching and noise texture to create the Aurora Borealis effect.

Shader code
shader_type spatial;

uniform float speed = 0.02;
uniform vec4 color : hint_color;
uniform float emission_strength = 5.0;
uniform sampler2D noise;
uniform float offset = 0.0;
uniform float smoothness = 0.15;
uniform float distort = 1.0;
uniform float scale = 1.0;

varying vec3 world_camera;
varying vec3 world_position;

const float STEP = 0.001;
const float BASE_DENSITY = 5.0;

float amplify(float value) {
	float magic_number = 0.166504;
	float output = 0.0;
	value = clamp(value, 0.0, 1.0);
	value = pow(value, 2);
	output += pow(magic_number, 4) * value;
	value = pow(value, 2);
	output += magic_number * value;
	value = pow(value, 2);
	output += value;
	return output;
}

float interpolate_noise(vec2 uv1, vec2 uv2) {
	return smoothstep(
		-smoothness, smoothness, texture(noise, uv1).r - texture(noise, uv2).r
	);
}

float random_wave(vec2 uv) {
	vec2 uv_distort = texture(noise, uv).rr * distort * 0.5;
	vec2 uv1 = uv * scale + vec2(TIME * speed, TIME * speed - offset) + uv_distort;
	vec2 uv2 = uv * scale + vec2(TIME * speed + 0.5, TIME * speed + offset) + uv_distort;
	float interpolated_noise = interpolate_noise(uv1, uv2);
	float intensity = 0.2 + clamp((0.5 - abs(interpolated_noise - 0.5)) * 1.5, 0.0, 1.0);
	float wave = amplify(intensity);
	return wave;
}

float ray_march(vec3 ray_origin, vec3 ray_direction, float start, float time) {
	float density = 0.0;
	float dist = start + STEP;
	
	while (true) {
		vec3 point = ray_origin + ray_direction * (dist);
		// Check if the point is outside of the mesh (-1 to 1 in all directions)
		if (clamp(point, vec3(-1, -1, -1), vec3(1, 1, 1)) != point) {
			break;
		}
		vec2 uv = vec2((point.x + 1.0) * 0.5, (point.z + 1.0) * 0.5);
		float wave_value = random_wave(uv);
		float extra_noise = texture(noise, vec2(point.y, 0.0)).r;
		float height_factor = (1.0 - point.y) * 0.5;
		float point_density = BASE_DENSITY * STEP * height_factor * wave_value * extra_noise;
		density += point_density;
		dist += STEP;
	}
	
	return density;
}

void vertex() {
	world_position = VERTEX;
	// Use object space
	world_camera = (inverse(MODELVIEW_MATRIX) * vec4(0, 0, 0, 1)).xyz;
}

void fragment() {
	vec3 ray_origin = world_camera;
	vec3 ray_direction =  normalize(world_position - ray_origin);
	float density = ray_march(
		ray_origin, ray_direction, length(world_camera - world_position), TIME
	);
	
	ALBEDO = color.rgb * density;
	EMISSION = color.rgb * density * emission_strength;
	ALPHA = density;
}
Tags
aurora borealis, northern lights, raymarching
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 miskatonicstudio

UV light (2D and 3D)

Pride

Engine flame

Subscribe
Notify of
guest

6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Muffin
Muffin
1 year ago

Line 54 (pasted below) results in an Error “Expected expression, found:” in godot 3.5; no idea how to fix

if (clamp(point, vec3(-1, -1, -1), vec3(1, 1, 1)) != point) {
Scarm
1 year ago
Reply to  Muffin

do -1.0 and 1.0

godot 3.5+ now requires float specifications

superintendent chalmers
superintendent chalmers
1 year ago

Ah- Aurora Borealis!? At this time of year, at this time of day, in this part of the country, localized entirely within your computer!?

Dmitry Zajarchenko
Dmitry Zajarchenko
11 months ago

may I see it?

Rogotch
Rogotch
9 months ago

Looks great! But when I change mesh size, shader stopped working

Rogotch
Rogotch
9 months ago
Reply to  Rogotch

oh, nevermind. I found where set size