Volumetric Aurora Borealis with Polar Reflection

This high-performance shader simulates a cinematic Aurora Borealis (Northern Lights) in a 360-degree virtual sky. It uses a specialized polynomial sample stride technique to render large atmospheric volumes efficiently, allowing the light trails to extend deep into the sky without the heavy computational cost typically associated with volumetric clouds.

The shader features:

  • Procedural Trail Generation: Uses a custom triNoise2d function to create non-smooth variations that mimic the “curtain” effect of real auroras.

  • Ray-Marched Atmosphere: A 50-step volumetric loop that calculates emission curves and smooth transparency.

  • Dynamic Skybox: Includes a procedural star field and a bi-color gradient background.

  • Ground Reflection: Automatically calculates a mirror reflection for the lower half of the screen, including water-like distortion for a complete environment feel.

🎮 Parameters (Uniforms)

Parameter Type Description
aurora_color vec4 The primary tint of the aurora curtains.
background_color1/2 vec4 The two colors used for the sky gradient (Zenith/Horizon).
aurora_intensity float Controls the brightness and bloom-like emission of the lights.
star_brightness float Adjusts the visibility of the procedural star field.
Shader code
shader_type canvas_item;

uniform vec4 aurora_color : source_color = vec4(0.84, 0.840, 0.90, 1.0); // Color principal de la aurora
uniform vec4 background_color1 : source_color = vec4(0.05, 0.1, 0.2, 1.0);
uniform vec4 background_color2 : source_color = vec4(0.1, 0.05, 0.2, 1.0);
uniform float aurora_intensity : hint_range(0.0, 5.0) = 1.8;
uniform float star_brightness : hint_range(0.0, 1.0) = 0.8;

#define PI 3.14159265358979323846264


mat2 mm2(float a) {
    float c = cos(a), s = sin(a);
    return mat2(vec2(c, s), vec2(-s, c));
}

const mat2 m2 = mat2(vec2(0.95534, 0.29552), vec2(-0.29552, 0.95534));

float tri(float x) {
    return clamp(abs(fract(x) - 0.5), 0.01, 0.49);
}

vec2 tri2(vec2 p) {
    return vec2(tri(p.x) + tri(p.y), tri(p.y + tri(p.x)));
}

float triNoise2d(vec2 p, float spd) {
    float z = 1.8;
    float z2 = 2.5;
    float rz = 0.;
    p *= mm2(p.x * 0.06);
    vec2 bp = p;
    for (float i = 0.; i < 5.; i++) {
        vec2 dg = tri2(bp * 1.85) * 0.75;
        dg *= mm2(TIME * spd);
        p -= dg / z2;

        bp *= 1.3;
        z2 *= .45;
        z *= .42;
        p *= 1.21 + (rz - 1.0) * .02;

        rz += tri(p.x + tri(p.y)) * z;
        // CORRECCIÓN: Multiplicación por -1.0 para invertir la matriz
        p *= (m2 * -1.0);
    }
    return clamp(1. / pow(rz * 29., 1.3), 0., .55);
}

float hash21(vec2 n) {
    return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}


vec4 aurora(vec3 ro, vec3 rd, vec2 fragCoord) {
    vec4 col = vec4(0);
    vec4 avgCol = vec4(0);

    for(float i=0.; i<50.; i++) {
        float of = 0.006 * hash21(fragCoord) * smoothstep(0., 15., i);
        float pt = ((.8 + pow(i, 1.4) * .002) - ro.y) / (rd.y * 2. + 0.4);
        pt -= of;
        vec3 bpos = ro + pt * rd;
        vec2 p = bpos.zx;
        float rzt = triNoise2d(p, 0.06);
        vec4 col2 = vec4(0, 0, 0, rzt);

        vec3 color_variation = (sin(1. - vec3(2.15, -0.5, 1.2) + i * 0.043) * 0.5 + 0.5);
        col2.rgb = aurora_color.rgb * color_variation * rzt;

        avgCol = mix(avgCol, col2, 0.5);
        col += avgCol * exp2(-i * 0.065 - 2.5) * smoothstep(0., 5., i);
    }
    col *= (clamp(rd.y * 15. + 0.4, 0., 1.));
    return col * aurora_intensity;
}


vec3 nmzHash33(vec3 q) {
    uvec3 p = uvec3(ivec3(q));
    p = p * uvec3(374761393U, 1103515245U, 668265263U) + p.zxy + p.yzx;
    p = p.yzx * (p.zxy ^ (p >> 3U));
    return vec3(p ^ (p >> 16U)) * (1.0 / 4294967295.0);
}

vec3 stars(vec3 p, vec2 res) {
    vec3 c = vec3(0.);
    float res_val = res.x;
    for (float i=0.; i<4.; i++) {
        vec3 q = fract(p * (0.15 * res_val)) - 0.5;
        vec3 id = floor(p * (0.15 * res_val));
        vec2 rn = nmzHash33(id).xy;
        float c2 = 1. - smoothstep(0., 0.6, length(q));
        c2 *= step(rn.x, 0.0005 + i * i * 0.001);
        c += c2 * (mix(vec3(1.0, 0.49, 0.1), vec3(0.75, 0.9, 1.0), rn.y) * 0.1 + 0.9);
        p *= 1.3;
    }
    return c * c * star_brightness;
}

vec3 bg(vec3 rd) {
    float sd = dot(normalize(vec3(-0.5, -0.6, 0.9)), rd) * 0.5 + 0.5;
    sd = pow(sd, 5.);
    vec3 col = mix(background_color1.rgb, background_color2.rgb, sd);
    return col * 0.63;
}


void fragment() {
    vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;

    vec3 ro = vec3(0, 0, -6.7);
    vec2 uv_sphere = FRAGCOORD.xy / iResolution.xy;
    float theta = (uv_sphere.y) * PI;
    float phi = (uv_sphere.x - 0.5) * 2.0 * PI;
    vec3 rd = vec3(sin(theta) * sin(phi), sin(theta) * cos(phi), cos(theta));

    float time_rot = TIME * 0.05;
    rd.yz *= mm2(0.4);
    rd.xz *= mm2(sin(time_rot) * 0.2);

    vec3 col = vec3(0.);
    float fade = smoothstep(0., 0.01, abs(rd.y)) * 0.1 + 0.9;

    col = bg(rd) * fade;

    if (rd.y > 0.) {
        vec4 aur = smoothstep(0., 1.5, aurora(ro, rd, FRAGCOORD.xy)) * fade;
        col += stars(rd, iResolution);
        col = col * (1. - aur.a) + aur.rgb;
    } else {
        // Reflejos
        vec3 rrd = rd;
        rrd.y = abs(rrd.y);
        col = bg(rrd) * fade * 0.6;
        vec4 aur = smoothstep(0.0, 2.5, aurora(ro, rrd, FRAGCOORD.xy));
        col += stars(rrd, iResolution) * 0.1;
        col = col * (1. - aur.a) + aur.rgb;

        vec3 pos = ro + ((0.5 - ro.y) / rrd.y) * rrd;
        float nz2 = triNoise2d(pos.xz * vec2(0.5, 0.7), 0.);
        col += mix(vec3(0.2, 0.25, 0.5) * 0.08, vec3(0.3, 0.3, 0.5) * 0.7, nz2 * 0.4);
    }

    COLOR = vec4(col, 1.0);
}
Live Preview
Tags
atmospheric, aurora, godotshader, nature, Procedural, raymarching, reflection, skybox, space, 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

Snake Game

Noise-Displaced Space Sphere

Star Wars-Style 3D Hologram Shader

Related shaders

2d aurora borealis

Aurora Borealis

Polar Coordinate Black Hole

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments