precision highp float; uniform vec2 resolution; uniform vec2 mouse; uniform float time; uniform sampler2D backbuffer; out vec4 outColor; #define DEFAULT 0.0 #define BLOOM 1.0 #define MAT_BOX 1.0 #define MAT_BOX_FRAME 2.0 #define MAT_BOX_TORUS 3.0 float pi = acos(-1.0); struct RayInfo{ vec3 camPos; vec3 rayDir; vec3 color; bool isHit; vec3 reflectionAttenuation; }; mat2 rotate(float a){ float c = cos(a); float s = sin(a); return mat2(c, -s, s, c); } float repeat(float p, float repCoef){ return (fract(p/repCoef - 0.5) - 0.5) * repCoef; } 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); } 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); } float random1d2d(vec2 p){ return fract(sin(dot(p.xy, vec2(12.575, 78.2356)))*43578.2356); } vec2 polarMod(vec2 p, float r){ float a = atan(p.y, p.x) + pi/r; float n = 2.0 * pi / r; a = floor(a/n)*n; return p * rotate(-a); } float sdBoxFrame(vec3 p, vec3 b, vec3 e) { vec3 q1 = abs(p) - b; vec3 q2 = abs(q1+e) - e; return min(min( length(max(vec3(q1.x, q2.y, q2.z), 0.0)) + min(max(q1.x, max(q2.y, q2.z)), 0.0), length(max(vec3(q2.x, q1.y, q2.z), 0.0)) + min(max(q2.x, max(q1.y, q2.z)), 0.0)), length(max(vec3(q2.x, q2.y, q1.z), 0.0)) + min(max(q2.x, max(q2.y, q1.z)), 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); } vec3 optionMin(vec3 a, vec3 b) { return (a.x < b.x) ? a : b; } vec3 sdBoxWithFrame(vec3 p, vec3 s, float w){ vec3 d = vec3(10e8, 0.0, DEFAULT); d = optionMin(d, vec3(sdBox(p, s - vec3(w)), MAT_BOX, DEFAULT)); d = optionMin(d, vec3(sdBoxFrame(p, s, vec3(w)), MAT_BOX_FRAME, BLOOM)); return d; } float sdBox2d(vec2 p, vec2 s){ p = abs(p) - s; return length(max(p, 0.0))+min(max(p.x, p.y), 0.0); } float sdTorusKnots(vec3 p, float inRadius, float outRadius, float divide){ vec2 cp = vec2(length(p.xz) - outRadius, p.y); float a = atan(p.x, p.z); cp *= rotate(a*3.0); cp.y = abs(cp.y)-0.01; float d = sdBox2d(cp, vec2(inRadius, inRadius*2.0)*sin(divide*a+time*divide)); return d; } vec3 sdTorusWithFrame(vec3 p){ vec3 d = vec3(10e8, 0.0, DEFAULT); d = optionMin(d, vec3(sdTorusKnots(p, 0.001, 0.021, 3.0), MAT_BOX_TORUS, DEFAULT)); d = optionMin(d, vec3(sdTorusKnots(p, 0.0012, 0.02, 3.0), MAT_BOX_FRAME, BLOOM)); return d; } vec3 distanceFunction(vec3 p){ vec3 d = vec3(10e8, 0.0, DEFAULT); float it = time*2.0; float fTime = mod(it, 16.0); float t1 = linearStep(2.0, 2.5, fTime); float t2 = linearStep(5.0, 5.5, fTime); float t3 = linearStep(8.0, 8.5, fTime); float t4 = linearStep(11.0, 11.5, fTime); float t5 = linearStep(14.0, 14.5, fTime); vec3 p1 = p; p1.z -= time*0.3; float rotateCoef = 0.0; rotateCoef = mix(0.0, 0.8, easeInOutExpo(t1)); rotateCoef = mix(rotateCoef, 0.4, easeInOutExpo(t2)); rotateCoef = mix(rotateCoef, 0.9, easeInOutExpo(t3)); rotateCoef = mix(rotateCoef, 1.4, easeInOutExpo(t4)); rotateCoef = mix(rotateCoef, 0.0, easeInOutExpo(t5)); p1.xy *= rotate(rotateCoef*p1.z); p1.z = repeat(p1.z, 0.5); float offsetParamSub = 0.0; offsetParamSub = mix(0.42, 0.34, easeInOutExpo(t1)); offsetParamSub = mix(offsetParamSub, 0.30, easeInOutExpo(t2)); offsetParamSub = mix(offsetParamSub, 0.43, easeInOutExpo(t3)); offsetParamSub = mix(offsetParamSub, 0.35, easeInOutExpo(t4)); offsetParamSub = mix(offsetParamSub, 0.42, easeInOutExpo(t5)); for(int i = 0; i < 4; i++){ p1.xy = polarMod(p1.xy, 4.0); p1 = abs(p1) - offsetParamSub; p1.xz *= rotate(0.38); p1.yz *= rotate(0.26); } d = optionMin(d, sdBoxWithFrame(p1, vec3(0.03, 0.25, 0.25), 0.005)); vec3 p2 = p; p2.z -= 4.93; p2.xy *= rotate(pi/2.0); p2.yz *= rotate(time); d = optionMin(d, sdTorusWithFrame(p2)); vec3 p3 = p; p3.z -= 4.93; p3.xy *= rotate(time*0.2); p3.yz *= rotate(time); d = optionMin(d, sdTorusWithFrame(p3)); 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 )); } 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); } float fresnelSchlick(float f0, float c){ return f0 + (1.0 - f0) * pow((1.0 - c), 5.0); } 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); } vec3 getBloomAlbedo(vec3 p, float materialId) { if(materialId == MAT_BOX_FRAME){ return hsv2rgb(sin(p.z*6.2)+time*0.5, 0.7, 0.7); } return vec3(0.0); } RayInfo rayMarch(vec3 camPos, vec3 rayDir, vec3 reflectionAttenuation, float rand){ RayInfo info; info.camPos = camPos; info.rayDir = rayDir; info.color = vec3(0.0); info.isHit = false; info.reflectionAttenuation = reflectionAttenuation; vec3 p; float d = 0.0; vec3 df = vec3(0.0); for(int i = 0; i < 160; i++){ p = camPos + rayDir * d; df = distanceFunction(p); float dist = df.x; float gProperty = df.z; if(gProperty == DEFAULT){ if(dist <= 0.001){ info.isHit = true; break; } d += dist * 0.25; }else{ info.color += 0.001/abs(dist) * getBloomAlbedo(p, df.y); d += abs(dist) * 0.25; } } if(info.isHit){ vec3 normal = getNormal(p); float metalic = 0.0; vec3 albedo = vec3(0.0); vec3 ld = normalize(-p); vec3 ref = reflect(rayDir, normal); float f0 = 1.0; if(df.y == MAT_BOX){ albedo = vec3(0.4588, 0.3843, 0.3843); metalic = 1.0; } if(df.y == MAT_BOX_TORUS){ albedo = hsv2rgb(sin(atan(p.y, p.x)*0.2+time*0.2), 0.8, 0.7); metalic = 1.0; } float diffuse = clamp(dot(normal, ld), 0.0, 1.0); float specular = pow(clamp(dot(reflect(ld, normal), rayDir) ,0.0, 1.0), 10.0); float ao = getAO(p, normal); float shadow = getSoftShadow(p, ld, 0.25, 3.0); info.color += albedo * diffuse * shadow * (1.0 - metalic); info.color += albedo * specular * shadow * metalic; info.color += albedo * ao * mix(vec3(0.0), vec3(1.0), 0.7); info.reflectionAttenuation *= albedo * fresnelSchlick(f0, dot(ref, normal)); info.camPos = p + 0.01 * normal; info.rayDir = ref; } info.color *= smoothstep(4.0, 0.0, d); return info; } vec3 getCutInUv(vec2 uv){ float timer = time*2.0; int index = int(floor(mod(timer, 30.0))); float expCoef = -20.0; if(index == 0){ float iUvY = floor((uv.y * 0.5 + 0.5) * 8.0); uv.x += (step(mod(iUvY, 2.0), 0.0) - 0.5) * exp(expCoef * fract(timer)) * 5.0; }else if(index == 14){ float iUvX = floor((uv.x * 0.5 + 0.5) * 10.0); uv.y += (step(1.0 - mod(iUvX, 2.0), 0.0) - 0.5) * exp(expCoef * fract(timer)) * 5.0; } float reflectFlag = index >= 14 ? 1.0 : 0.0; return vec3(uv, reflectFlag); } vec3 renderingFunc(vec2 uv){ vec3 uvElement = getCutInUv(uv); uv = uvElement.xy; float flag = uvElement.z; vec3 color = vec3(0.0); vec3 camPos = vec3(0.0, 0.0, 5.0); vec3 lookPos = vec3(0.0, 0.0, 0.0); vec3 forward = normalize(lookPos - camPos); vec3 up = vec3(0.0, 1.0, 0.0); vec3 right = normalize(cross(forward, up)); up = normalize(cross(right, forward)); float fov = 1.0; vec3 rayDir = normalize(uv.x * right + uv.y * up + fov * forward); float rand = random1d2d(uv); vec3 ra = vec3(1.0); float d = 0.0; if(flag == 0.0){ for(int i = 0; i < 1; i++){ RayInfo info = rayMarch(camPos, rayDir, ra, rand); color += info.reflectionAttenuation * info.color * ra; if(!info.isHit){ break; } ra = info.reflectionAttenuation; camPos = info.camPos; rayDir = info.rayDir; } } else{ for(int i = 0; i < 3; i++){ RayInfo info = rayMarch(camPos, rayDir, ra, rand); color += info.reflectionAttenuation * info.color * ra; if(!info.isHit){ break; } ra = info.reflectionAttenuation; camPos = info.camPos; rayDir = info.rayDir; } } color = acesFilm(color*0.8); color = pow(color, vec3(0.4545)); return color; } void main(){ vec2 uv = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y); vec2 texUv = vec2(gl_FragCoord.xy/resolution); vec3 color = vec3(0.0); color += renderingFunc(uv); outColor = vec4(color, 1.0); }