precision highp float;
uniform vec2 resolution;
uniform float time;
out vec4 outColor;

#define MATERIAL_DISH 0.0
#define MATERIAL_DESK 1.0
#define MATERIAL_CANDLE 2.0
#define MATERIAL_CAKE 3.0
#define MATERIAL_ROOM 4.0
#define MATERIAL_DESK_FOOT 5.0
#define MATERIAL_STRAWBERRY 6.0
#define MATERIAL_FLAME 7.0
#define MATERIAL_SPOTLIGHT 8.0
#define MATERIAL_PARTICLE 9.0
#define MATERIAL_BOARD 10.0

float pi = acos(-1.0);
float jitter = 0.0;
float ft;
float pAt = 0.0;

float random1d1d(float v)
{
    return fract(sin(v * 924.5326) * 12457.214);
}

float random1d2d(vec2 p){
    return fract(sin(dot(p.xy, vec2(12.575, 78.2356)))*43578.2356);
}

float random3d1d(vec3 v) { 
	return fract(sin(dot(v, vec3(12.9898, 78.233, 19.8321))) * 43758.5453);
}

float valueNoise(vec3 v) {
	vec3 i = floor(v);
	vec3 f = smoothstep(0.0, 1.0, fract(v));
	return  mix(
		mix(
			mix(random3d1d(i), random3d1d(i + vec3(1.0, 0.0, 0.0)), f.x),
			mix(random3d1d(i + vec3(0.0, 1.0, 0.0)), random3d1d(i + vec3(1.0, 1.0, 0.0)), f.x),
			f.y
		),
		mix(
			mix(random3d1d(i + vec3(0.0, 0.0, 1.0)), random3d1d(i + vec3(1.0, 0.0, 1.0)), f.x),
			mix(random3d1d(i + vec3(0.0, 1.0, 1.0)), random3d1d(i + vec3(1.0, 1.0, 1.0)), f.x),
			f.y
		),
		f.z
	);
}

float fbm(vec3 v) {
	float n = 0.0;
	float a = 0.5;
	for (int i = 0; i < 5; i++) {
		n += a * valueNoise(v);
		v *= 2.0;
		a *= 0.5;
	}
	return n;
}

vec3 hsv2rgb(float h, float s, float v){
    vec3 rgb = clamp(abs(mod(h * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
    rgb = rgb * rgb * (3.0 - 2.0 * rgb);
    return v * mix(vec3(1.0), rgb, s);
}

vec2 random2dPolar(float n){
    float x = fract(sin(n*546.25)*222.223)*pi*2.0;
    float y = (fract(sin(n*222.25)*622.223) - 0.5)*5.0;

    return vec2(cos(x), sin(x))*y;
}

vec2 random2d(float n){
    float x = (fract(sin(n*246.25)*422.223) - 0.5)*2.0;
    float y = (fract(sin(n*522.25)*722.223) - 0.5)*2.0;

    return vec2(x, y);
}

// Coding a fireworks effect : https://www.youtube.com/watch?v=xDxAnguEOn8
float explode(vec2 pos, float t, float coef){
    float c = 0.0;

    for(float i = 0.0; i <= 10.0; i+=1.0){
        vec2 dir = random2dPolar(i+floor(t)+coef*100.0);
        vec2 p = pos - dir*t;
        float d = dot(p, p);
        float b = mix(0.0, 0.0005, smoothstep(1.0, 0.0, t));
        c += b/d;
    }

    return c;
}


mat2 rotate(float a)
{
    float c = cos(a);
    float s = sin(a);
    return mat2(c, -s, s, c);
}


float bounceOut(float t) {
	const float a = 4.0 / 11.0;
	const float b = 8.0 / 11.0;
	const float c = 9.0 / 10.0;
	
	const float ca = 4356.0 / 361.0;
	const float cb = 35442.0 / 1805.0;
	const float cc = 16061.0 / 1805.0;
	
	float t2 = t * t;
	
	return t < a
		? 7.5625 * t2
		: t < b
		? 9.075 * t2 - 9.9 * t + 3.4
		: t < c
		? ca * t2 - cb * t + cc
		: 10.8 * t * t - 20.52 * t + 10.72;
}

float bounceIn(float t) {
  return 1.0 - bounceOut(1.0 - t);
}

float easeInOutExpo(float t) {
    if (t == 0.0 || t == 1.0) {
        return t;
    }
    if ((t *= 2.0) < 1.0) {
        return 0.5 * pow(2.0, 10.0 * (t - 1.0));
    } else {
        return 0.5 * (-pow(2.0, -10.0 * (t - 1.0)) + 2.0);
    }
}

float linearStep(float start, float end, float t){
    return clamp((t - start)/(end - start), 0.0, 1.0);
}

vec2 polarMod(vec2 p, float r)
{
    float a =  pi / r - atan(p.x, p.y);
    float n = (pi * 2.0) / r;
    a = floor(a/n)*n;
    return p * rotate(-a);
}

vec2 optionMin(vec2 a, vec2 b)
{
    return (a.x < b.x) ? a : b;
}

float smoothMin(float a, float b, float k){
    float h = clamp(0.5 + 0.5 * (b-a)/k, 0.0, 1.0);
    return mix(b, a, h) - k * h * (1.0 - h);
}

float sdCappedCylinder(vec3 p, float h, float r)
{
    vec2 d = abs(vec2(length(p.xz), p.y)) - vec2(r, h);
    return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}

float sdBox(vec3 p, vec3 s)
{
    vec3 q = abs(p) - s;
    return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}

float sdSphere(vec3 p, float r)
{
    return length(p) - r;
}

// https://neort.io/art/c78r3o43p9f3hsjeassg
float sdSphere(vec3 iPos, vec3 fPos, vec3 c){
    float r = random3d1d(iPos + c);
    if(r > 0.95){
        r = fract(sin(r)) * 0.01;
    }
    else{ 
        r =- 0.5;
    }

    return length(fPos - c) - r;
}

// https://neort.io/art/c78r3o43p9f3hsjeassg
float sdSphereR(vec3 p){
    float d = 0.0;
    p.y += time * 2.4;
    vec3 iPos = floor(p);
    vec3 fPos = fract(p);

    d += sdSphere(iPos, fPos, vec3(0.0, 0.0, 0.0));
    d = min(d, sdSphere(iPos, fPos, vec3(0.0, 0.0, 1.0)));
    d = min(d, sdSphere(iPos, fPos, vec3(0.0, 1.0, 0.0)));
    d = min(d, sdSphere(iPos, fPos, vec3(1.0, 0.0, 0.0)));
    d = min(d, sdSphere(iPos, fPos, vec3(1.0, 1.0, 0.0)));
    d = min(d, sdSphere(iPos, fPos, vec3(1.0, 0.0, 1.0)));
    d = min(d, sdSphere(iPos, fPos, vec3(0.0, 1.0, 1.0)));
    d = min(d, sdSphere(iPos, fPos, vec3(1.0, 1.0, 1.0)));

    return d;
}

vec2 sdDish(vec3 p){
    p.y += 0.2;
    float d = sdCappedCylinder(p, 0.01, 1.5);
    d = smoothMin(d, sdCappedCylinder(p - vec3(0.0, 0.2, 0.0), 0.04, 3.0), 0.25);

    vec3 p1 = p;
    p1.xz = polarMod(p1.xz, 40.0);
    d = smoothMin(d, sdSphere(p1 - vec3(0.0, 0.2, 3.0), 0.02), 0.3);

    vec3 p2 = p;
    p2.xz *= rotate(pi*0.025);
    p2.xz = polarMod(p2.xz, 10.0);
    d = smoothMin(d, sdSphere(p2 - vec3(0.0, 0.3, 3.0), 0.02), 0.3);
    return vec2(d, MATERIAL_DISH);
}

vec2 sdCake(vec3 p){
    p.y -= 1.0;
    float d = sdCappedCylinder(p, 1.0, 2.0);

    vec3 p1 = p;
    p1.xz = polarMod(p1.xz, 120.0);
    d = smoothMin(d, sdSphere(p1 - vec3(0.0, 0.7, 2.0), 0.2), 0.6);
    vec3 p2 = p;
    p2.xz *= rotate(pi*0.25);
    p2.xz = polarMod(p2.xz, 100.0);
    d = smoothMin(d, sdSphere(p2 - vec3(0.0, -0.6, 2.0), 0.4), 0.8);

    p.y -= 1.0;
    d = smoothMin(d, sdCappedCylinder(p, 1.0, 1.0), 0.6);
    
    vec3 p3 = p;
    p2.xz *= rotate(pi*0.25);
    p3.xz = polarMod(p3.xz, 100.0);
    d = smoothMin(d, sdSphere(p3 - vec3(0.0, 0.8, 0.8), 0.2), 0.5);

    vec3 p4 = p;
    p4.xz *= rotate(pi*0.025);
    p4.xz = polarMod(p4.xz, 12.0);
    p4.z -= 1.7;
    p4.xz = polarMod(p4.xz, 12.0);
    p4 -= vec3(0.0, 0.2, 0.1);

    d = smoothMin(d, sdSphere(p4, 0.1), 0.2);

    return vec2(d, MATERIAL_CAKE);
}

vec2 sdCakeDecorate(vec3 p)
{
    vec2 d = vec2(10e8);
    vec3 p1 = p;
    p1.xz *= rotate(pi*0.025);
    p1.xz = polarMod(p1.xz, 12.0);
    float berry = 10e8;
    berry = min(berry, sdSphere(p1 - vec3(0.0, 2.3, 1.7), 0.2));
    berry = smoothMin(berry, sdSphere(p1 - vec3(0.0, 2.6, 1.7), 0.01), 0.3);
    d = optionMin(d, vec2(berry, MATERIAL_STRAWBERRY));

    return d;
}

vec2 sdFlame(vec3 p)
{
    vec2 d = vec2(10e8);
    vec3 p1 = p;

    float tF = linearStep(27.0, 28.0, ft);
    float fRadius1 = 0.12 - mix(0.0, 0.12, easeInOutExpo(tF));
    float fRadius2 = 0.06 - mix(0.0, 0.06, easeInOutExpo(tF));
    float flame1 = 10e8;
    flame1 = min(flame1, sdSphere(p1 - vec3(0.0, 3.85, 0.0), fRadius1));
    flame1 = smoothMin(flame1, sdSphere(p1 - vec3(sin(time + floor(length(p1.x)))*0.1, 3.9 + (fract(time*2.0)*0.2 + 0.1)*0.8, 0.0), fRadius2  * (1.0 - fract(time*1.0))), 0.2 * (1.0 - fract(time*1.0)));
    d = optionMin(d, vec2(flame1, MATERIAL_FLAME));

    vec3 p2 = p;
    p2.xz *= rotate(pi*0.025);
    p2.xz = polarMod(p2.xz, 6.0);
    float flame2 = 10e8;
    float fRadius3 = 0.05 - mix(0.0, 0.05, easeInOutExpo(tF));
    float fRadius4 = 0.04 - mix(0.0, 0.04, easeInOutExpo(tF));
    flame2 = min(flame2, sdSphere(p2 - vec3(0.0, 3.45, 0.8), fRadius3));
    flame2 = smoothMin(flame2, sdSphere(p2 - vec3(sin(time + random1d1d(floor(p2.x) * 100.0))*0.05, 3.55 + (fract(time*2.0 + floor(p2.x))*0.2 + 0.1)*0.4, 0.8), fRadius4 * (1.0 - fract(time*1.0))), 0.2  * (1.0 - fract(time*1.0)));
    d = optionMin(d, vec2(flame2, MATERIAL_FLAME));
    return d;
}

vec2 sdCandle(vec3 p){
    p.y -= 2.0;
    float d = sdCappedCylinder(p, 1.8, 0.1);

    vec3 p1 = p;
    p1.xz *= rotate(pi*0.025);
    p1.xz = polarMod(p1.xz, 6.0);
    d = min(d, sdCappedCylinder(p1 - vec3(0.0, 0.0, 0.8), 1.4, 0.06));
    
    return vec2(d, MATERIAL_CANDLE);
}

vec2 sdDesk(vec3 p){
    p.y += 0.4;
    float d = sdBox(p, vec3(4.8, 0.05, 4.8));
    return vec2(d, MATERIAL_DESK);
}

vec2 sdDeskFoot(vec3 p)
{
    float d = 10e8;
    p.y += 3.4;
    d = smoothMin(d, sdBox(p - vec3(4.5, 0.0, 4.5), vec3(0.5, 3.0, 0.5)), 0.2);
    d = smoothMin(d, sdBox(p - vec3(4.5, 0.0, -4.5), vec3(0.5, 3.0, 0.5)), 0.2);
    d = smoothMin(d, sdBox(p - vec3(-4.5, 0.0, 4.5), vec3(0.5, 3.0, 0.5)), 0.2);
    d = smoothMin(d, sdBox(p - vec3(-4.5, 0.0, -4.5), vec3(0.5, 3.0, 0.5)), 0.2);

    d = smoothMin(d, sdBox(p - vec3(0.0, 2.6, -4.5), vec3(5.0, 0.5, 0.5)), 0.2);
    d = smoothMin(d, sdBox(p - vec3(0.0, 2.6, 4.5), vec3(5.0, 0.5, 0.5)), 0.2);
    d = smoothMin(d, sdBox(p - vec3(-4.5, 2.6, 0.0), vec3(0.5, 0.5, 5.0)), 0.2);
    d = smoothMin(d, sdBox(p - vec3(4.5, 2.6, 0.0), vec3(0.5, 0.5, 5.0)), 0.2);

    return vec2(d, MATERIAL_DESK_FOOT);
}

vec2 sdSpotLight(vec3 p, vec3 offset)
{
    vec2 d = vec2(10e8);

    float lightLen = 30.0;
    vec3 p1 = p - offset;
    float fR = easeInOutExpo(linearStep(1.0, 2.0, ft));
    float r = mix(0.0, 0.3 + length(p1) * 0.3, fR);
    d = optionMin(d, vec2(sdCappedCylinder(p1 + vec3(0.0, lightLen, 0.0), lightLen, r), MATERIAL_SPOTLIGHT));

    return d;
}

vec2 sdBoard(vec3 p)
{
    float tB= linearStep(7.0, 17.0, ft);
    vec2 d = vec2(10e8);

    p.y -= 40.0;
    float yPos = 40.0 * tB;
    p.y += yPos;
    float bFrame = 10e8;
    bFrame = min(bFrame, sdBox(p - vec3(0.0, 5.0, 15.0), vec3(20.0, 10.0, 1.5)));
    bFrame = min(bFrame, sdBox(p - vec3(10.0, 40.0, 15.0), vec3(0.5, 40.0, 1.5)));
    bFrame = min(bFrame, sdBox(p - vec3(-10.0, 40.0, 15.0), vec3(0.5, 40.0, 0.5)));
    bFrame = max(bFrame, -sdBox(p - vec3(0.0, 5.0, 15.0), vec3(20.0, 10.0, 1.7)));
    d = optionMin(d, vec2(bFrame, MATERIAL_DESK_FOOT));

    d = optionMin(d, vec2(sdBox(p - vec3(0.0, 5.0, 15.0), vec3(20.0, 10.0, 0.8)), MATERIAL_BOARD));

    return d;
}

vec2 distanceFunction(vec3 p)
{
    vec2 d = vec2(10e8, 0.0);
    d = optionMin(d, sdDish(p));
    d = optionMin(d, sdCake(p));
    d = optionMin(d, sdCandle(p));
    d = optionMin(d, sdFlame(p));
    d = optionMin(d, sdCakeDecorate(p));
    d = optionMin(d, sdDesk(p));
    d = optionMin(d, sdDeskFoot(p));
    d = optionMin(d, sdBoard(p));

    vec2 b3 = vec2(-sdBox(p - vec3(0.0, 20.0, 0.0), vec3(60.0, 30.0, 60.0)), MATERIAL_ROOM);
    d = optionMin(d, b3);

    d = optionMin(d, vec2(sdSphereR(p), MATERIAL_PARTICLE));

    pAt += 0.01/(0.01 + abs(sdSphereR(p)));

    return d;
}

vec3 getNormal(vec3 p)
{
    vec2 err = vec2(0.001, 0.0);
    return normalize(vec3(
        distanceFunction(p + err.xyy).x - distanceFunction(p - err.xyy).x,
        distanceFunction(p + err.yxy).x - distanceFunction(p - err.yxy).x,
        distanceFunction(p + err.yyx).x - distanceFunction(p - err.yyx).x
    ));
}

vec3 volumetric(vec3 p){
    vec3 col = vec3(0.0);
    col += fbm(p + vec3(time*0.92, 0.0, 0.0)) * 0.02;
    return col;
}

vec3 roomVolumetric(vec3 p){
    vec2 uv = p.xz * 1.0;

    vec3 col = vec3(0.0);
    vec2 grid = smoothstep(0.45, 0.4, fract(uv) - 0.5);
    vec2 cell = floor(uv);
    col += min(grid.x, grid.y);
    col *= vec3(random1d2d(cell + 78.214), random1d2d(cell + 38.214), random1d2d(cell + 57.214));
    return col;
}

float getAO(vec3 p, vec3 n){
    float occ = 0.0;
    float sca = 1.0;

    for(int i = 0; i < 5; i++){
        float h = 0.01 + 0.12 * float(i) / 4.0;
        float d = distanceFunction(p + h * n).x;
        occ += (h - d) * sca;
        if(occ > 0.35){
            break;
        }
    }

    return clamp(1.0 - 3.0 * occ, 0.0, 1.0) * (0.5 + 0.5 * n.y);
}

float getSoftShadow(vec3 camPos, vec3 rayDir, float tMin, float tMax){
    float tp = (0.8 - camPos.y) / rayDir.y;
    if(tp > 0.0){
        tMax = min(tMax, tp);
    }

    float res = 1.0;
    float t = tMin;
    for(int i = 0; i < 24; i++){
        float h = distanceFunction(camPos + rayDir * t).x;
        float s = clamp(8.0 * h / t, 0.0, 1.0);
        res = min(res, s * s * (3.0 - 2.0 * s));
        t += clamp(h, 0.02, 0.2);
        if(res < 0.004 || tMax < t){
            break;
        }
    }

    return clamp(res, 0.0, 1.0);
}

vec3 material(vec3 p, vec3 n, vec3 rayDir, vec2 df, float fog){
    vec3 color = vec3(0.0);
    vec3 roomColor = vec3(1.0);
    float metalic = 0.0;
    vec3 albedo = vec3(0.0);
    vec3 emissive = vec3(0.0);

    if(df.y == MATERIAL_DISH){
        albedo = mix(vec3(0.6549, 0.6784, 0.5059), vec3(1.0, 1.0, 1.0), fbm(vec3(length(p)*100.0)));
        metalic = 0.3;
        emissive = vec3(0.6)*pow(length(p.xz * 0.37), 10.0);
    }
    if(df.y == MATERIAL_DESK){
        albedo = mix(vec3(0.0, 0.0, 0.0), vec3(0.8745, 0.4549, 0.1098), fbm(vec3(p.x, p.yy)));
    }
    if(df.y == MATERIAL_CANDLE){
        albedo = vec3(0.7294, 0.8745, 0.8353);
        emissive = vec3(0.4);
    }
    if(df.y == MATERIAL_CAKE){
        albedo = vec3(1.0);
        emissive = vec3(0.4);
    }
    if(df.y == MATERIAL_ROOM){
        vec3 rp = p * 0.25;
        albedo += roomVolumetric(rp);
        albedo += 2.0 / (2.0 + length(p.xz));
        metalic = 0.8;
    }
    if(df.y == MATERIAL_DESK_FOOT){
        albedo = vec3(1.0);
        metalic = 0.9;
        emissive = vec3(0.4);
    }
    if(df.y == MATERIAL_STRAWBERRY){
        albedo = vec3(0.9294, 0.0863, 0.0863);
        metalic = 0.1;
        emissive = vec3(0.4039, 0.0275, 0.0275);
    }
    if(df.y == MATERIAL_FLAME){
        albedo = mix(vec3(0.9765, 0.7333, 0.2392), vec3(0.9098, 0.5098, 0.5098), smoothstep(3.85, 4.0, p.y));
        metalic = 0.1;
        emissive = vec3(0.9098, 0.0706, 0.0706);
    }
    if(df.y == MATERIAL_PARTICLE){
        albedo += pAt * 0.2;
    }
    if(df.y == MATERIAL_BOARD){
        float t8 = easeInOutExpo(linearStep(19.0, 21.0, ft));
        float tF = easeInOutExpo(linearStep(27.0, 28.0, ft));
        vec2 uv2 = vec2(((p.xy + vec2(10.0, 5.2)) / vec2(20.0, 20.0)) - 0.5);
        for(float i = 0.0; i <= 50.0; i+=1.0){
            float t = time+i/50.0;
            float ft = floor(t);
            vec2 offset = random2d(i+2.0+ft);
            float coef = random1d1d(i+2.0+ft+ft);
            albedo += explode(uv2 - offset, fract(t), coef)*hsv2rgb(coef, 1.0, 1.0);
        }
        albedo *= (t8 - tF);
    }

    vec3 lightDir = normalize(vec3(1.0, 2.0, -3.0));

    float diff = clamp(dot(n, lightDir), 0.0, 1.0);
    float specular = pow(clamp(dot(reflect(lightDir, n), rayDir), 0.0, 1.0), 10.0);
    float ao = getAO(p, n);
    float shadow = getSoftShadow(p, lightDir, 0.22, 4.0);
    color += albedo * diff * shadow * (1.0 - metalic);
    color += albedo * specular * shadow * metalic;
    color += albedo * clamp(0.5 + 0.5 * n.y, 0.0, 1.0) * 0.2;
    color += albedo * ao * roomColor;
    color += emissive;
    return color;
}

vec3 acesFilm(vec3 col){
    float a = 2.51;
    float b = 0.03;
    float c = 2.43;
    float d = 0.59;
    float e = 0.14;
    return clamp((col * (a * col + b)) / (col * (c * col + d) + e), 0.0, 1.0);
}

float lightDistanceFunction(vec3 p)
{
    float lightDF = 1.0 - sdSpotLight(p,  vec3(0.0, 30.0, 0.0)).x;
	return min(max(0.0, lightDF), 1.0);
}

vec3 renderingFunc(vec2 uv){
    ft = mod(time, 30.0);

    float t1 = linearStep(1.0, 2.0, ft);
    float t2 = linearStep(4.0, 5.0, ft);

    float t3 = linearStep(7.0, 8.0, ft);
    float t4 = linearStep(9.0, 10.0, ft);
    float t5 = linearStep(11.0, 12.0, ft);
    float t6 = linearStep(13.0, 14.0, ft);
    float t7 = linearStep(15.0, 16.0, ft);
    float camZ = -25.0 + mix(0.0, 6.0, t3) + mix(0.0, 5.0, t4) + mix(0.0, 4.0, t5) + mix(0.0, 3.0, t6) + mix(0.0, 2.0, t7);

    float t33 = bounceIn(linearStep(11.0, 12.0, ft));
    float t44 = bounceIn(linearStep(13.0, 14.0, ft));
    float t55 = bounceIn(linearStep(15.0, 16.0, ft));
    float t66 = bounceIn(linearStep(13.0, 14.0, ft));
    float t77 = bounceIn(linearStep(15.0, 16.0, ft));
    float camY = 7.0 + mix(0.0, -0.8, t33) + mix(0.0, -0.6, t44) + mix(0.0, -0.4, t55) + mix(0.0, -0.2, t66) + mix(0.0, -0.1, t77);

    vec3 color = vec3(0.0);
    vec3 camPos = vec3(0.0, camY, camZ);;
    vec3 lookPos = vec3(0.0, 3.0, 0.0);
    vec3 up = vec3(0.0, 1.0, 0.0);
    vec3 forward = normalize(lookPos - camPos);
    vec3 right = normalize(cross(up, forward));
    up = normalize(cross(forward, right));
    float fov = 1.0;//0.2 + tick(time*1.2, 1.8, 10.0)*0.8;
    vec3 rayDir = normalize(uv.x * right + uv.y * up + fov * forward);
    float rand = random1d2d(uv);

    float t8 = easeInOutExpo(linearStep(18.0, 20.0, ft));
    float t9 = easeInOutExpo(linearStep(22.0, 24.0, ft));
    float camAngle = mix(0.0, -0.5, t8 - t9);
    camPos.yz *= rotate(camAngle);
    rayDir.yz *= rotate(camAngle);

    vec3 p = camPos;
    vec2 df = vec2(0.0);
    float d = 0.0;
    bool isHit = false;
    float dd = 0.0;
    for(int i = 0; i < 200; i++){
        p = camPos + rayDir * d;
        df = distanceFunction(p);
        if(df.x > 100.0){
            dd = 100.0;
            break;
        }
        if(df.x <= 0.0001){
            isHit = true;
            break;
        }
        d += df.x;
        dd += df.x;
    }

    float density = 0.;
    float stepSize = 0.1;
    vec3 stepRay = stepSize * rayDir;
    vec3 p2 = camPos+stepRay*rand;
    float stepDist = rand*stepSize;
    float stepLength = 0.8;
    vec4 sum = vec4(0.0, 0.0, 0.0, 1.0);
    vec3 at = vec3(0.0);
    for(int i = 0; i < 100; i++){
        if(stepDist > d){
            break;
        }

        at += pow(volumetric(p2) * 4.2, vec3(2.0));
        stepDist += stepSize;
        p2 += stepRay;
    }

    // Referenct : https://www.shadertoy.com/view/WdXGRj
    vec3 p3 = camPos + rayDir * rand * stepLength;
    for (int i = 0; i < 100; i++)
    {
        if (sum.a < 0.1) {
        	break;
        }
        float d = lightDistanceFunction(p3);
    
        if( d > 0.001)
        {
            density = clamp((d / 100.0)*10.0, 0.0, 1.0);
            sum.rgb += vec3(density);
            sum.a *= 1.0 - density;
        }
        p3 += rayDir * stepLength;
    }

    if(isHit){
        vec3 normal = getNormal(p);
        float fogRangeCoef = mix(10.0, 50.0, easeInOutExpo(t1));
        float fog = 1.0 - clamp(dd/fogRangeCoef, 0.0, 1.0);
        vec3 mat = material(p, normal, rayDir, df, fog);
        color += mat;
        color *= fog;
        color *= sum.rgb * (sum.a * 30.0) * at * t1;
        color = mix(color, mat * fog + sum.rgb * (sum.a * 3.0) * at, t2);
        float t9 = linearStep(29.0, 30.0, ft);
        color = mix(color, vec3(0.0), easeInOutExpo(t9));
    }

    color = acesFilm(color * 0.8);
    color = pow(color, vec3(1.0/2.2));

    return color;
}

void main(){
    vec2 uv = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
    vec3 color = vec3(0.0);
    jitter = random1d1d(uv.x + uv.y * 57.0);

    color += renderingFunc(uv);

    outColor = vec4(color, 1.0);
}