par-term 0.32.1

Cross-platform GPU-accelerated terminal emulator with inline graphics support (Sixel, iTerm2, Kitty)
/*! par-term shader metadata
name: singularity
author: null
description: null
version: 1.0.0
defaults:
  animation_speed: 0.5
  brightness: 0.25
  channel0: ''
  channel1: null
  channel2: null
  channel3: null
  cubemap: textures/cubemaps/env-outside
  cubemap_enabled: false
  use_background_as_channel0: null
  uniforms:
    iCenterDarkness: 1.0
    iCenterOffset: 0.19999996
    iColorGradientB: -1.0
    iColorGradientRG:
    - 0.6
    - -0.4
    iDiskBrightness: 1.0
    iDiskScale: 1.0
    iExposure: 1.0
    iGravityStrength: 0.19999999
    iPerspectiveBase: 0.099999994
    iRimLight: 0.030000001
    iSpinSpeed: 0.19999996
    iSpiralScale: 5.0
    iSpiralTwist: 0.49999994
    iTurbulence: 0.7
    iWaveCount: 9
    iWaveDrift: 0.5
    iZoom: 0.7
*/

/*
    "Singularity" by @XorDev
    A whirling blackhole.
    https://www.shadertoy.com/view/3csSWB

    Adapted for par-term background shader.
*/

#define MAX_WAVE_COUNT 16

// control slider min=-0.6 max=0.6 step=0.01 label="Center Offset"
uniform float iCenterOffset;
// control slider min=0.35 max=1.5 step=0.01 label="Zoom"
uniform float iZoom;
// control slider min=0.01 max=1 step=0.01 scale=log label="Perspective Base"
uniform float iPerspectiveBase;
// control slider min=0.01 max=1.5 step=0.01 scale=log label="Gravity Strength"
uniform float iGravityStrength;
// control slider min=-2 max=2 step=0.01 label="Spin Speed"
uniform float iSpinSpeed;
// control slider min=-2 max=2 step=0.01 label="Spiral Twist"
uniform float iSpiralTwist;
// control slider min=1 max=12 step=0.05 label="Spiral Scale"
uniform float iSpiralScale;
// control slider min=0 max=2 step=0.01 label="Turbulence"
uniform float iTurbulence;
// control slider min=0 max=2 step=0.01 label="Wave Drift"
uniform float iWaveDrift;
// control int min=1 max=16 step=1 label="Wave Count"
uniform int iWaveCount;
// control slider min=0.25 max=3 step=0.01 label="Disk Scale"
uniform float iDiskScale;
// control slider min=0.1 max=3 step=0.01 label="Disk Brightness"
uniform float iDiskBrightness;
// control slider min=0.1 max=3 step=0.01 label="Center Darkness"
uniform float iCenterDarkness;
// control slider min=0.001 max=0.2 step=0.001 scale=log label="Rim Light"
uniform float iRimLight;
// control slider min=0.1 max=4 step=0.01 scale=log label="Exposure"
uniform float iExposure;
// control vec2 min=-2 max=2 step=0.01 label="Color Gradient RG"
uniform vec2 iColorGradientRG;
// control slider min=-2 max=2 step=0.01 label="Color Gradient B"
uniform float iColorGradientB;

float activeWaveMask(int index, int count) {
    return step(float(index) + 0.5, float(count));
}

void mainImage(out vec4 O, in vec2 fragCoord)
{
    // Resolution and centered coordinates
    vec2 r = iResolution.xy;
    vec2 p = (fragCoord * 2.0 - r) / (r.y * max(iZoom, 0.001));

    // Diagonal vector and blackhole center
    vec2 d = vec2(-1.0, 1.0);
    vec2 b = p - iCenterOffset * d;

    // Perspective transformation
    float perspective = iPerspectiveBase + iGravityStrength / max(dot(b, b), 0.0001);
    vec2 c = p * mat2(1.0, 1.0, -1.0 / perspective, 1.0 / perspective);

    // Spiral rotation
    float a = max(dot(c, c), 0.0001);
    float angle = iSpiralTwist * log(a) + iTime * iSpinSpeed;
    float cosA = cos(angle);
    mat2 spiralMat = mat2(cosA, cos(angle + 33.0), cos(angle + 11.0), cosA);

    // Rotate into spiraling coordinates
    vec2 v = (c * spiralMat) * iSpiralScale;

    // Wave accumulation loop
    vec4 w = vec4(0.0);
    int waveCount = clamp(iWaveCount, 1, MAX_WAVE_COUNT);
    for (int i = 0; i < MAX_WAVE_COUNT; i++) {
        float mask = activeWaveMask(i, waveCount);
        float j = float(i + 1);
        float invJ = 1.0 / j;
        v += (iTurbulence * sin(v.yx * j + iTime) * invJ + iWaveDrift) * mask;
        vec2 sv = sin(v);
        w += (1.0 + sv.xyxy) * mask;
    }

    // Accretion disk
    float diskRadius = length(sin(v * 3.333) * 0.4 + c * (3.0 + d) * iDiskScale);
    float diskBright = (2.0 + diskRadius * (diskRadius * 0.25 - 1.0)) * iDiskBrightness;

    // Lighting factors
    float centerDark = 0.5 + iCenterDarkness / a;
    float rimLight = iRimLight + abs(length(p) - 0.7);

    // Combine: gradient / (waveColor * diskBright * centerDark * rimLight)
    vec3 gradientRGB = vec3(iColorGradientRG, iColorGradientB);
    vec4 gradient = exp(c.x * vec4(gradientRGB, 0.0));
    float combined = max(diskBright * centerDark * rimLight, 0.0001);
    O = 1.0 - exp(-gradient * iExposure / max(w.xyyx * combined, vec4(0.0001)));
}