0.00
60.0 fps

Portal / Void

Fully customizable

Log in to post a comment.

#version 300 es
precision highp float;

uniform float iTime;
uniform vec2 iResolution;

// ==== BASE EFFECT ====
uniform float angleDensity;      // value=3.0,  min=1.0,  max=20.0, step=0.01
uniform float distanceDensity;   // value=1.0,  min=0.0,  max=20.0, step=0.01
uniform float spotBrightness;    // value=0.3,  min=0.0,  max=2.0,  step=0.01
uniform float brightness;        // value=0.3,  min=0.0,  max=2.0,  step=0.01
uniform float contrast;          // value=1.0,  min=0.0,  max=4.0,  step=0.01
uniform float velocity;          // value=0.2,  min=-2.0, max=2.0,  step=0.01

// ==== EFFECT COLORS ====
uniform vec3  colorInner;        // value=1.0,0.4,0.9
uniform vec3  colorOuter;        // value=0.2,0.7,1.0

// ==== BACKGROUND ====
uniform vec3  bgInner;           // value=0.04,0.02,0.08
uniform vec3  bgOuter;           // value=0.00,0.00,0.01
uniform float bgGradientPower;   // value=1.0, min=0.1, max=4.0, step=0.01

// ==== ANIMATION / MOTION ====
uniform float rotationSpeed;     // value=0.15, min=-5.0, max=5.0, step=0.01
uniform float pulseSpeed;        // value=1.5,  min=0.0, max=10.0, step=0.01
uniform float pulseAmount;       // value=0.12, min=0.0, max=1.0,  step=0.01

// ==== DISTORTION ====
uniform float distortAmount;     // value=0.03, min=0.0, max=0.5,  step=0.001
uniform float distortScale;      // value=8.0,  min=0.1, max=40.0, step=0.01
uniform float distortSpeed;      // value=1.0,  min=-10.0,max=10.0, step=0.01

// ==== RINGS / SHOCK WAVES ====
uniform float ringStrength;      // value=0.15, min=0.0, max=2.0,  step=0.01
uniform float ringScale;         // value=18.0, min=0.1, max=80.0, step=0.01
uniform float ringSpeed;         // value=2.0,  min=-20.0,max=20.0, step=0.01
uniform float ringSharpness;     // value=3.0,  min=1.0, max=16.0, step=0.01

// ==== STAR / ANGULAR FLARE ====
uniform float starStrength;      // value=0.12, min=0.0, max=2.0,  step=0.01
uniform float starArms;          // value=4.0,  min=1.0, max=12.0, step=0.01
uniform float starSharpness;     // value=10.0, min=1.0, max=40.0, step=0.01

// ==== DETAILS LAYER ====
uniform float detailStrength;    // value=0.35, min=0.0, max=2.0,  step=0.01
uniform float detailScale;       // value=2.5,  min=0.1, max=10.0, step=0.01
uniform float detailSpeed;       // value=0.3,  min=-5.0, max=5.0, step=0.01

// ==== FINISHING ====
uniform float bloomBoost;        // value=0.8,  min=0.0, max=4.0,  step=0.01
uniform float vignette;          // value=0.25, min=0.0, max=2.0,  step=0.01
uniform float saturation;        // value=1.1,  min=0.0, max=3.0,  step=0.01

in  vec2 vScreen;
out vec4 fragColor;

// ------------------------------------------------------------
// Hash without Sine (David Hoskins)
// ------------------------------------------------------------
float hash13(vec3 p3) {
    p3  = fract(p3 * 0.1031);
    p3 += dot(p3, p3.yzx + 33.33);
    return fract((p3.x + p3.y) * p3.z);
}

float noise(vec3 x) {
    vec3 p = floor(x);
    vec3 f = smoothstep(0.0, 1.0, fract(x));

    return mix(
        mix(
            mix(hash13(p + vec3(0,0,0)), hash13(p + vec3(1,0,0)), f.x),
            mix(hash13(p + vec3(0,1,0)), hash13(p + vec3(1,1,0)), f.x),
            f.y
        ),
        mix(
            mix(hash13(p + vec3(0,0,1)), hash13(p + vec3(1,0,1)), f.x),
            mix(hash13(p + vec3(0,1,1)), hash13(p + vec3(1,1,1)), f.x),
            f.y
        ),
        f.z
    );
}

const mat3 m3 = mat3(
    -0.7373,  0.4562,  0.4980,
     0.0000, -0.7373,  0.6754,
     0.6754,  0.4980,  0.5437
) * 2.0;

float fbm(vec3 p) {
    float a = 1.0;
    float n = 0.0;
    for (int i = 0; i < 5; i++) {
        n += abs(noise(p) * 2.0 - 1.0) * a;
        a *= 0.5;
        p *= m3;
    }
    return n;
}

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

vec3 saturateColor(vec3 c, float sat) {
    float luma = dot(c, vec3(0.299, 0.587, 0.114));
    return mix(vec3(luma), c, sat);
}

void main() {
    vec2 uv = vScreen;                  // предполагается диапазон примерно [-1..1]
    float r = length(uv);
    float rr = max(r * r, 1e-4);

    // --- Rotation ---
    vec2 uvRot = rot2(iTime * rotationSpeed) * uv;

    // --- Distortion (subtle heat/plasma wobble) ---
    vec2 duv = uvRot;
    duv += vec2(
        sin(uvRot.y * distortScale + iTime * distortSpeed),
        cos(uvRot.x * distortScale - iTime * distortSpeed)
    ) * distortAmount;

    float rd = length(duv);
    vec2 dir = (rd > 1e-6) ? normalize(duv) : vec2(0.0);

    // --- Base noise field ---
    float zBase = rd * distanceDensity - iTime * velocity;
    float f1 = fbm(vec3(dir * angleDensity, zBase));

    // --- Detail layer (finer animated turbulence) ---
    float f2 = fbm(vec3(dir * angleDensity * detailScale, zBase * detailScale + iTime * detailSpeed));

    float f = f1 + detailStrength * f2;

    // --- Pulse ("breathing") ---
    float pulse = 1.0 + sin(iTime * pulseSpeed) * pulseAmount;
    f *= pulse;

    // --- Radial energy shaping ---
    f = (f * f) / rr;
    f += spotBrightness / rr;

    // --- Shock rings ---
    // ring signal strongest on bright areas; optional radial wave
    float rings = sin(rd * ringScale - iTime * ringSpeed);
    rings = pow(max(rings, 0.0), max(ringSharpness, 1.0)) * ringStrength;
    f += rings / (1.0 + rd * 2.0);

    // --- Angular star flare ---
    float ang = atan(duv.y, duv.x);
    float arms = max(starArms, 1.0);
    float star = pow(abs(cos(ang * arms)), max(starSharpness, 1.0)) * starStrength;
    f += star / rr;

    // --- Global brightness ---
    f *= brightness;
    f = max(f, 0.0);

    // --- Background gradient (behind the effect) ---
    float bgT = pow(clamp(smoothstep(0.0, 1.25, r), 0.0, 1.0), max(bgGradientPower, 0.001));
    vec3 bg = mix(bgInner, bgOuter, bgT);

    // --- Radial color gradient for the glow itself ---
    float colorT = clamp(smoothstep(0.0, 1.0, r), 0.0, 1.0);
    vec3 glowColor = mix(colorInner, colorOuter, colorT);

    // --- Tone response for the effect ---
    vec3 effect = 1.0 - exp(-glowColor * pow(f, max(contrast, 0.001)));
    effect = clamp(effect, 0.0, 1.0);

    // --- Cheap bloom-like boost on hot areas ---
    vec3 hot = effect * effect * bloomBoost;
    effect = clamp(effect + hot, 0.0, 1.0);

    // --- Composite: background behind shader ---
    float effectMask = clamp(max(effect.r, max(effect.g, effect.b)), 0.0, 1.0);
    vec3 col = mix(bg, effect, effectMask);

    // --- Saturation ---
    col = saturateColor(col, saturation);

    // --- Vignette ---
    float vig = 1.0 - smoothstep(0.35, 1.35, r) * vignette;
    col *= clamp(vig, 0.0, 1.0);

    fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);
}