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);
}