Plasma / Warp Tunnel - psychedelic hyperspace effect

15 views 0 replies
Live Shader
Loading versions...

Hey all, been working on a plasma warp tunnel shader this weekend and finally got it to a place I'm happy with. Figured I'd share it here.

The idea was to combine a classic plasma effect with a radial tunnel warp so you get this swirling hyperspace look. I'm using it as a loading screen transition in my game - when the player enters a portal it kicks in for a couple seconds while the next level streams in. Works great as a background for menu screens too, or honestly just as a screensaver if you're into that.

The colors cycle through the full spectrum and the whole thing rotates and pulses, so it's pretty hypnotic. You can tweak the speed, color palette, and tunnel depth by adjusting the constants at the top.

precision mediump float;
uniform vec2 iResolution;
uniform float iTime;

void main() {
    vec2 uv = (gl_FragCoord.xy - 0.5 * iResolution.xy) / min(iResolution.x, iResolution.y);

    float angle = atan(uv.y, uv.x);
    float radius = length(uv);

    // tunnel warp - invert radius for depth effect
    float tunnelDepth = 0.4 / (radius + 0.05);
    float tunnelAngle = angle / 3.14159;

    // scrolling tunnel coordinates
    float tx = tunnelDepth + iTime * 0.8;
    float ty = tunnelAngle + iTime * 0.15;

    // plasma layers
    float p1 = sin(tx * 3.0 + iTime) * cos(ty * 4.0 - iTime * 0.7);
    float p2 = sin(ty * 5.0 + iTime * 1.3) * sin(tx * 2.5 - iTime * 0.5);
    float p3 = cos(tx * 4.0 + ty * 3.0 + iTime * 0.9);
    float p4 = sin(length(vec2(tx, ty) * 2.0) - iTime * 1.1);

    float plasma = p1 + p2 + p3 + p4;
    plasma *= 0.25;

    // swirl distortion
    float swirl = sin(angle * 3.0 + radius * 8.0 - iTime * 2.0) * 0.3;
    plasma += swirl;

    // color mapping - cycle through vibrant hues
    vec3 col;
    col.r = sin(plasma * 3.14159 + iTime * 0.4) * 0.5 + 0.5;
    col.g = sin(plasma * 3.14159 + iTime * 0.4 + 2.094) * 0.5 + 0.5;
    col.b = sin(plasma * 3.14159 + iTime * 0.4 + 4.188) * 0.5 + 0.5;

    // boost saturation
    col = pow(col, vec3(0.85));

    // vignette and tunnel fade
    float vignette = 1.0 - smoothstep(0.2, 1.8, radius);
    float tunnelGlow = smoothstep(0.0, 0.15, radius);

    // bright center pulse
    float centerPulse = exp(-radius * 6.0) * (sin(iTime * 3.0) * 0.3 + 0.7);
    vec3 pulseColor = vec3(0.9, 0.85, 1.0) * centerPulse;

    col = col * vignette * tunnelGlow + pulseColor;

    // subtle scanline for extra flavor
    col *= 0.95 + 0.05 * sin(gl_FragCoord.y * 1.5);

    gl_FragColor = vec4(col, 1.0);
}

Some notes on what's going on:

  • The tunnel effect comes from inverting the radius (`0.4 / radius`) which maps screen space into a cylinder stretching away from the camera
  • Four overlapping sine/cosine plasma layers create the organic swirling patterns
  • The swirl distortion ties the plasma to the polar angle so everything spirals around the center
  • Color is generated by phase-shifting RGB channels through the plasma value, giving you that full rainbow cycle
  • There's a bright pulsing center that acts like you're flying toward a light source
  • The subtle scanline at the end is optional but adds a nice retro touch

Feel free to mess with the multipliers on the plasma layers to get different looks. Making `p1` through `p4` use prime-number multipliers gives you less repetitive patterns. You can also clamp the colors to a narrower palette if full rainbow is too much for your art style.

Would love to see variations if anyone plays with it!