0.00
60.0 fps

Log in to post a comment.

#version 300 es
precision highp float;

uniform float iTime;
uniform vec2 iResolution;
uniform vec4 iMouse;

in vec2 vScreen;
out vec4 fragColor;
void mainImage(out vec4 colOut, in vec2 fragCoord);

void main()
{
    vec2 fragCoord = (vScreen * 0.5 + 0.5) * iResolution;
    mainImage(fragColor, fragCoord);
}
    // END: shadertoy porting template

    #define _Speed 2.0//disk rotation speed

    #define _Steps 5.0//disk texture layers
    #define _Size 0.3//size of BH



float hash(float x){ return fract(sin(x)*152754.742); }
float hash(vec2 x){ return hash(x.x + hash(x.y)); }

float value(vec2 p, float f)//value noise
{
    float bl = hash(floor(p * f + vec2(0.0, 0.0)));
    float br = hash(floor(p * f + vec2(1.0, 0.0)));
    float tl = hash(floor(p * f + vec2(0.0, 1.0)));
    float tr = hash(floor(p * f + vec2(1.0, 1.0)));

    vec2 fr = fract(p * f);
    fr = (3.0 - 2.0 * fr)*fr * fr;
    float b = mix(bl, br, fr.x);
    float t = mix(tl, tr, fr.x);
    return mix(b, t, fr.y);
}

vec4 raymarchDisk(vec3 ray, vec3 zeroPos)
{
    //return vec4(1.0,1.0,1.0,0.0); //no disk

    vec3 position = zeroPos;
    float lengthPos = length(position.xz);
    float dist = min(1.0, lengthPos*(1.0 / _Size) *0.5) * _Size * 0.4 *(1.0 / _Steps) /(abs(ray.y));

    position += dist * _Steps * ray * 0.5;

    vec2 deltaPos;
    deltaPos.x = -zeroPos.z * 0.01 + zeroPos.x;
    deltaPos.y = zeroPos.x * 0.01 + zeroPos.z;
    deltaPos = normalize(deltaPos - zeroPos.xz);

    float parallel = dot(ray.xz, deltaPos);
    parallel /= sqrt(lengthPos);
    parallel *= 0.5;
    float redShift = parallel +0.3;
    redShift *= redShift;

    redShift = clamp(redShift, 0.0, 1.0);

    float disMix = clamp((lengthPos - _Size * 2.0)*(1.0 / _Size)*0.24, 0.0, 1.0);
    vec3 insideCol =mix(vec3(1.0, 0.8, 0.0), vec3(0.5, 0.13, 0.02)*0.2, disMix);

    insideCol *= mix(vec3(0.4, 0.2, 0.1), vec3(1.6, 2.4, 4.0), redShift);
    insideCol *= 1.25;
    redShift += 0.12;
    redShift *= redShift;

    vec4 o = vec4(0.0);

    for (float i = 0.0; i < _Steps; i++)
    {
        position -= dist * ray;

        float intensity =clamp(1.0 - abs((i - 0.8) * (1.0 / _Steps) * 2.0), 0.0, 1.0);
        float lengthPos = length(position.xz);
        float distMult = 1.0;

        distMult *=clamp((lengthPos -_Size * 0.75) * (1.0 / _Size) * 1.5, 0.0, 1.0);
        distMult *= clamp((_Size * 10.0 -lengthPos) * (1.0 / _Size) * 0.20, 0.0, 1.0);
        distMult *= distMult;

        float u = lengthPos + iTime* _Size * 0.3 + intensity * _Size * 0.2;

        vec2 xy;
        float rot = mod(iTime * _Speed, 8192.0);
        xy.x = -position.z * sin(rot) + position.x * cos(rot);
        xy.y = position.x * sin(rot) + position.z * cos(rot);

        float x = abs(xy.x/(xy.y));
        float angle = 0.02 * atan(x);

        const float f = 70.0;
        float noise = value(vec2(angle, u * (1.0 / _Size) * 0.05), f);
        noise = noise * 0.66 + 0.33 * value(vec2(angle, u * (1.0 / _Size) * 0.05), f * 2.0);

        float extraWidth =noise * 1.0 * (1.0 -clamp(i * (1.0 / _Steps)*2.0 - 1.0, 0.0, 1.0));

        float alpha = clamp(noise*(intensity + extraWidth)*((1.0 / _Size) * 10.0+ 0.01) *dist * distMult, 0.0, 1.0);

        vec3 col = 2.0 * mix(vec3(0.3, 0.2, 0.15)*insideCol, insideCol, min(1.0, intensity * 2.0));
        o = clamp(vec4(col * alpha + o.rgb*(1.0 - alpha), o.a*(1.0 - alpha) + alpha), vec4(0.0), vec4(1.0));

        lengthPos *= (1.0 / _Size);

        o.rgb+= redShift*(intensity * 1.0 + 0.5)* (1.0 / _Steps) * 100.0 * distMult/(lengthPos * lengthPos);
    }

    o.rgb = clamp(o.rgb - 0.005, 0.0, 1.0);
    return o;
}


void Rotate(inout vec3 vector, vec2 angle)
{
    vector.yz = cos(angle.y)*vector.yz
    +sin(angle.y)*vec2(-1, 1)*vector.zy;
    vector.xz = cos(angle.x)*vector.xz
    +sin(angle.x)*vec2(-1, 1)*vector.zx;
}

void mainImage(out vec4 colOut, in vec2 fragCoord)
{
    colOut = vec4(0.0);;

    vec2 fragCoordRot;
    fragCoordRot.x = fragCoord.x * 0.985 + fragCoord.y * 0.174;
    fragCoordRot.y = fragCoord.y * 0.985 - fragCoord.x * 0.174;
    fragCoordRot += vec2(-0.06, 0.12) * iResolution.xy;

    //setting up camera
    vec3 ray = normalize(vec3((fragCoordRot - iResolution.xy*.5)/iResolution.x, 1));
    vec3 pos = vec3(0.25, 0.2, -6.5);
    vec2 angle = vec2(iTime * 0.1, .2);
    angle.y = 2.0 * 3.14 + 0.1 + 3.14;
    float dist = length(pos);
    Rotate(pos, angle);
    angle.xy -= min(.3 / dist, 3.14) * vec2(1, 0.5);
    Rotate(ray, angle);

    vec4 col = vec4(0.0);
    vec4 glow = vec4(0.0);
    vec4 outCol =vec4(100.0);

    for (int disks = 0; disks< 20; disks++)//steps
    {

        for (int h = 0; h < 6; h++)//reduces tests for exit conditions (to minimise branching)
        {
            float dotpos = dot(pos, pos);
            float invDist = inversesqrt(dotpos);//1 / distance to BH
            float centDist = dotpos * invDist;//distance to BH
            float stepDist = 0.92 * abs(pos.y /(ray.y));//conservative distance to disk (y==0)
            float farLimit = centDist * 0.5;//limit step size far from to BH
            float closeLimit = centDist * 0.1 + 0.05 * centDist * centDist*(1.0 / _Size);//limit step size closse to BH
            stepDist = min(stepDist, min(farLimit, closeLimit));

            float invDistSqr = invDist * invDist;
            float bendForce = stepDist * invDistSqr * _Size * 0.625;//bending force
            ray =normalize(ray - (bendForce * invDist)*pos);//bend ray towards BH
            pos += stepDist * ray;

            glow += vec4(1.2, 1.1, 1, 1.0) *(0.01 * stepDist * invDistSqr * invDistSqr *clamp(centDist*(2.0) - 1.2, 0.0, 1.0));//adds fairly cheap glow
        }

        float dist2 = length(pos);

        if (dist2 < _Size * 0.1)//ray sucked in to BH
        {
            outCol =vec4(col.rgb * col.a + glow.rgb *(1.0 - col.a), 1.0);
            break;
        }

        else if (dist2 > _Size * 1000.0)//ray escaped BH
        {
            outCol = vec4(col.rgb * col.a+ glow.rgb *(1.0 - col.a), 1.0);
            break;
        }

        else if (abs(pos.y) <= _Size * 0.002)//ray hit accretion disk
        {
            vec4 diskCol = raymarchDisk(ray, pos);//render disk
            pos.y = 0.0;
            pos += abs(_Size * 0.001 /ray.y) * ray;
            col = vec4(diskCol.rgb*(1.0 - col.a) + col.rgb, col.a + diskCol.a*(1.0 - col.a));
        }
    }

    //if the ray never escaped or got sucked in
    if (outCol.r == 100.0)
    outCol = vec4(col.rgb + glow.rgb *(col.a +glow.a), 1.0);

    col = outCol;
    col.rgb =pow(col.rgb, vec3(0.6));

    colOut += col;
}