Skip to contentCREATIVE·CODE·ART
1
1
1
1
1
GLSL shader

Aurora Ink

Licence: CC BY-NC-SA 4.0: remix with credit, non-commercial, share alike

View the code
// Aurora Ink: a TouchDesigner GLSL TOP for Creative Code Art.
// A feedback painting. Every frame, the last image is carried along a slowly turning
// current of noise and fades a little, while wandering lights pour new colour in.
// Nothing is stored: the picture is painted live, and no two moments are the same.
// Move your pointer over it to stir the ink.

uniform float uTime;
uniform vec2 uMouse;

uniform float uFlow;    // how fast the current carries the ink
uniform float uSwirl;   // size of the eddies: small values, big slow swirls
uniform float uTrail;   // how long the ink lingers
uniform float uHue;     // the palette
uniform float uGlow;    // how bright the lights are
uniform int uLights;    // how many lights wander

out vec4 fragColor;

// A current with no sinks (curl noise), so ink swirls instead of piling up.
vec2 current(vec3 p)
{
    const float e = 0.02;
    float a = TDSimplexNoise(p + vec3(0.0, e, 0.0)) - TDSimplexNoise(p - vec3(0.0, e, 0.0));
    float b = TDSimplexNoise(p + vec3(e, 0.0, 0.0)) - TDSimplexNoise(p - vec3(e, 0.0, 0.0));
    return vec2(a, -b) / (2.0 * e);
}

void main()
{
    vec2 uv = vUV.st;
    vec2 res = uTDOutputInfo.res.zw;
    float aspect = res.x / res.y;
    vec2 p = (uv - 0.5) * vec2(aspect, 1.0);
    float t = uTime;

    // The pointer is a soft whirlpool.
    vec2 m = (uMouse - 0.5) * vec2(aspect, 1.0);
    vec2 toM = p - m;
    float pull = exp(-dot(toM, toM) * 18.0);

    // Where this pixel's ink was a moment ago.
    vec2 v = current(vec3(p * uSwirl, t * 0.06)) + vec2(-toM.y, toM.x) * pull * 6.0;
    vec2 from = uv - v * uFlow * 0.0012 * vec2(1.0 / aspect, 1.0);
    vec3 ink = texture(sTD2DInputs[0], from).rgb;

    // Old ink fades, and its colour turns slowly, like oil on water.
    ink = mix(ink, ink.brg, 0.003);
    ink = max(ink * uTrail - 0.0015, 0.0);

    // The lights: each follows its own slow orbit and colour.
    vec3 light = vec3(0.0);
    for (int i = 0; i < 6; i++)
    {
        if (i >= uLights) break;
        float f = float(i);
        vec2 c = vec2(sin(t * (0.23 + f * 0.041) + f * 2.4) * 0.42 * aspect,
                      sin(t * (0.19 + f * 0.033) + f * 1.7) * 0.32);
        vec2 d = p - c;
        vec3 col = TDHSVToRGB(vec3(fract(uHue + f * 0.085 + 0.04 * sin(t * 0.4 + f)), 0.85, 1.0));
        light += col * exp(-dot(d, d) * 450.0);
    }

    // New light is measured against how long ink lingers, so long trails glow instead of burning to white.
    vec3 colour = ink + light * uGlow * (1.0 - uTrail) * 4.5;
    fragColor = TDOutputSwizzle(vec4(min(colour, vec3(1.0)), 1.0));
}