#version 460 precision mediump float; out vec4 o; const float PI = 3.14159265; const float TAU = (2. * PI); const float PHI = sqrt(5.) * 0.5 + 0.5; layout(location = 0) uniform float syncs[11]; layout(location = 20) uniform float fft_output[512]; // FFT_SIZE / 4 // float u_time = syncs[0]; // paletti muunnos: arg 0.8 --> 0.5 vec3 palette(float t, float arg, float arg2){ vec3 a=vec3(0.52,0.56,0.47); vec3 b=vec3(0.62,0.56,0.51); vec3 c=vec3(0.43,0.79,0.42); vec3 d=vec3(arg,0.42,arg2); return a+b*cos(6.28318*(c*t+d)); } vec2 getUV() { const vec2 u_resolution = vec2(1920, 1080); return ((gl_FragCoord.xy * 2. - u_resolution.xy) / u_resolution.y); //const vec2 scale = vec2(0.00104166667, 0.00185185185); //return gl_FragCoord.xy * scale - 1.0; } mat2 rot2D(float angle) { float s = sin(angle); float c = cos(angle); return mat2(c, -s, s, c); } float noise(in vec2 xy, in float seed) { return fract(tan(distance(xy * PHI, xy) * seed) * xy.x); } // shorted functions vec3 no(vec3 v) { return normalize(v); } float cl(float a, float b, float c) { return clamp(a,b,c); } float le(vec3 s) { return length(s); } ///////////////// // GEOMETRY // ///////////////// float fHexagonCircumcircle(vec3 p, vec2 h) { vec3 q = abs(p); return max(q.y - h.y, max(q.x * sqrt(3.) * 0.5 + q.z * 0.5, q.z) - h.x); } // Return local coordinates inside hex AND axial ID struct HexData { vec3 local; // Local position inside hex vec2 axial; // Axial ID (q, r) }; HexData hexTile(vec3 p, float radius) { float q = (sqrt(3.0) / 3.0 * p.x - 1.0 / 3.0 * p.z) / radius; float r = (2.0 / 3.0 * p.z) / radius; float rq = round(q); float rr = round(r); float rs = round(-q - r); float dq = abs(rq - q); float dr = abs(rr - r); float ds = abs(rs + q + r); if(dq > dr && dq > ds) rq = -rr - rs; else if(dr > ds) rr = -rq - rs; float hx = radius * sqrt(3.0) * (rq + rr * 0.5); float hz = radius * 1.5 * rr; HexData outData; outData.local = p - vec3(hx, 0.0, hz); outData.axial = vec2(rq, rr); // Hex ID return outData; } float hexDistance(vec2 axial) { float q = axial.x; float r = axial.y; float s = -q - r; return max(abs(q), max(abs(r), abs(s))); } float hexPylon(vec3 p, vec2 h) { //vec3 p = vec3(p.x, p.z, p2.y); vec3 b = vec3(h.x, h.y, h.x); // Hexagon. p.xz = abs(p.xz); p.xz = vec2(p.x * .866025 + p.z * .5, p.z); // The ".015" is a subtle rounding factor. Zero gives sharp edges, // and larger numbers give a more rounded look. return le(max(abs(p) - b + .15, 0.)) - .15; } ////////////// // SCENE // ////////////// // instructions -> opU( { float to union with } , vec2( {put shape here}, {put material here} ) ) vec2 opU(vec2 d1, vec2 d2) { return (d1.x < d2.x) ? d1 : d2; } float sdSphere(vec3 p, float r){ return length(p) -r; } // Scene mapping with occlusion-aware SDF blending vec2 mapScene(vec3 p) { float dist = 20.; int repeat = 0; if((length(p.xz)) < 2*dist){ repeat = 2; } if((length(p.xz)) < 1.5*dist){ repeat = 3; } if((length(p.xz)) < dist){ repeat = 5; } // mitigate neighbor occlusion with anti-bleed blending float minDist = 1e9; for (int dx = -repeat; dx <= repeat; ++dx) { for (int dy = -repeat; dy <= repeat; ++dy) { vec2 offset = vec2(dx, dy); vec3 hexpos = vec3(p.x-dx, p.y-8.0, p.z-dy); HexData hex = hexTile(hexpos, 1.1); float distFromCenter = hexDistance(hex.axial); int fftIndex = int(cl(distFromCenter + 1.0, 0.0, 511.0)); float fftVal = fft_output[fftIndex]; float noise = mix(noise(hex.axial+1., 0.1), noise(hex.axial+1., 0.2), sin(syncs[0] * 4.)); float hexHeight = clamp(1.0 + fftVal * 5.0 + noise, 0., 15.); vec3 r = vec3(hex.local.x + offset.x,hex.local.y,hex.local.z+offset.y); // r.yz *= rot2D(PI * 0.5); r.xz *= rot2D(0.5); vec3 cellPos = r; float d = fHexagonCircumcircle(cellPos, vec2(0.85, hexHeight)); minDist = min(minDist, d); } } return vec2(minDist,0.); } //////////////// // RAYCAST // //////////////// vec3 castRay(vec3 ro, vec3 rd, inout vec3 pos) { float mat = 0.; float hit = 0.; vec3 d; float t = 0.,ad,tmax=200.; // total distance travelled const float tolerance = 0.0001; const float Z_REPEAT_DIST = 1.5; vec2 res; // Raymarching for (int i = 0; i < 50; i++) { pos = ro + rd * t; res = mapScene(pos); // Get distance to objects ad = abs(res.x); mat = res.y; if (t > tmax) break; if (ad < tolerance*(t*0.00125 + 1.0)) { hit = 1.0; break; } t += res.x; // "march" the ray } // t -= Z_REPEAT_DIST/2.0; // // for( int i=0; i<20; i++ ) // { // vec3 pos2 = ro + rd * t; // res = mapScene(pos2); // get distance to objects // ad = abs(res.x); // mat = res.y; // if (ad < (tolerance)) // { // hit = 1.0; // pos = pos2; // break; // } // if (t > tmax) break; // t += min(d.x, Z_REPEAT_DIST/5.0); // "march" the ray // } return vec3(t, mat, hit); } //////////////// // SHADING // //////////////// float softshadow(in vec3 ro, in vec3 rd, float mint, float maxt, float w) { float res = 1.0; float t = mint; for(int i = 0; i < 6; i++) { if(t > maxt) break; float h = mapScene(ro + t * rd).x; res = min(res, h / (w * t)); t += clamp(h, 0.1, 0.80); if(res < -1.0) break; } res = max(res, -1.0); return 0.25 * (1.0 + res) * (1.0 + res) * (2.0 - res); } vec3 addPointLight(vec3 lightPos, vec3 lightColor, float intensity, vec3 worldPos, vec3 viewDir, vec3 normal) { // Light vector from surface to light float roughness = 1.0; vec3 lightDir = lightPos - worldPos; float lightDistance = length(lightDir); lightDir = normalize(lightDir); // Attenuation (quadratic falloff) float attenuation = intensity / (1.0 + 0.09 * lightDistance + 0.032 * lightDistance * lightDistance); // Diffuse lighting (Lambert) float NdotL = max(dot(normal, lightDir), 0.0); vec3 diffuse = lightColor * NdotL * attenuation; // Specular lighting (Blinn-Phong) vec3 halfDir = normalize(lightDir + (-viewDir)); float NdotH = max(dot(normal, halfDir), 0.0); float shininess = mix(128.0, 8.0, roughness); // Convert roughness to shininess vec3 specular = lightColor * pow(NdotH, shininess) * attenuation; // Fresnel effect vec3 F0 = vec3(0.04); // Base reflectance for dielectrics vec3 fresnel = F0 + (1.0 - F0) * pow(clamp(1.0 - max(dot(halfDir, lightDir), 0.0), 0.0, 1.0), 5.0); // Soft shadows float shadow = softshadow(worldPos + normal * 0.01, lightDir, 0.02, lightDistance, 4.0); // Combine diffuse and specular with shadow return (diffuse + specular * fresnel) * shadow * shadow; } vec3 calcNormal(vec3 pos) { vec2 e = vec2(.01, 0.); vec3 n = vec3(mapScene(pos + e.xyy).x - mapScene(pos - e.xyy).x, mapScene(pos + e.yxy).x - mapScene(pos - e.yxy).x, mapScene(pos + e.yyx).x - mapScene(pos - e.yyx).x); return no(n); } vec3 pal(float color) { color *= 0.2; vec3 c = palette(color, 0.25, 0.63); vec3 c2 = palette(color, 0.5 ,0.2); float t = clamp((syncs[0] - 129.0) / 2.0, 0.0, 1.0); // Smoothly ramps from 0 to 1 after 12s return mix(c, c2, t); // Blend between c and c2 over ~2 seconds //return c2; } vec3 applyFog(vec3 col, float t, vec3 rd, vec3 lightDir, float fogAmount) { float syncsBass = cl((syncs[1] + syncs[2] + syncs[3]), 0., 1.); float fogAmount2 = 1.0 - exp(-t * fogAmount); float sunAmount = max(dot(rd, lightDir), 1.0); // highlight color vec3 fogColor = mix(vec3(0.3, 0.3, 0.3), vec3(0.2, 0.2, 0.2), // Main color pow(sunAmount, syncsBass * 1.0)); return mix(col, fogColor, fogAmount2); } vec3 shading(vec3 p, vec3 n, vec3 dir, vec3 camPos) { vec3 outMaterial = vec3(0.0); outMaterial = pal(p.y*p.y*0.01); vec3 lights = vec3(0.); //lights += phongLighting(p, n, camPos, dir, vec3(0.51), outMaterial); lights += addPointLight(vec3(0., 20.0, 0.), vec3(0.77, 0.26, 0.73), 30.0, p, dir, n); // LIGHT CHANGING WITH CIRCLE RADIUS float maxRadius = 25.; // Circle radius float particleHeight = 15.; //(syncs[5] * 40.); float particlePos = (syncs[0] * 0.5) + syncs[5]; // Map param to angle float particleStartPos = particlePos * 2.0 * PI; // Direction from center to initial circle position (in XY plane) vec3 particleDir = normalize(vec3(cos(particleStartPos), 0.0, sin(particleStartPos))); // XZ direction float r = max(maxRadius - 0.0, maxRadius); vec3 particleOffset = vec3(0. , particleHeight, 0.); // particle offset // Final object position = center (offset) + radial movement vec3 center = particleOffset; // Circle center vec3 objPos = center + particleDir * r; // Object slides inward //res = opU(res, vec2(sdSphere(p - objPos, sphereRadius), 1.)); lights += addPointLight(objPos, vec3(0.33, 0.91, 0.93), 30.0, p, dir, n); vec3 lightDir = vec3(0., 2., 3); float ind = cl(dot(n, no(lightDir * vec3(.0, 1.0, -2.0))), 0.0, 1.0); //lights += vec3(0.08, 0.62, 0.75) * ind * 0.8; outMaterial *= max(vec3(0.), lights); // output with lights; return outMaterial; } vec3 postProcess(vec3 col) { // Contrast float contrast = 0.85; col = mix(col, smoothstep(0.0, 1.0, col), contrast); // Colour mapping //col *= vec3(1.0, 1.0, 1.0); // Gamma col = pow(col, vec3(.55)); // gamma 2.2 // fade in at the beginning //col*=vec3(clamp((u_time-1.8)*0.5,0., 1.)); // fade out at the end // col*=vec3(clamp((120.-u_time)*.35, 0., 1.)); return col; } ////////////////// // RENDERING // ////////////////// vec3 getCameraRayDir(vec2 uv, vec3 camPos, vec3 camTarget, float fov) { vec3 f = no(camTarget - camPos), r = no(cross(vec3(0, 1, 0), f)), u = cross(f, r), c = f * fov, i = c + uv.x * r + uv.y * u, d = no(i); return d; } vec3 render(vec2 uv) { vec3 camPos = vec3(-20.0 + sin(syncs[0] * 0.25) * 5, abs(sin(syncs[0] * 0.25) * 10) + 25.0, -20.0); vec3 camTarget = vec3(0.0, 0.0, 0.0); // Adjust target as needed float fov = 1.0; vec3 rayDir = getCameraRayDir(uv, camPos, camTarget, fov); vec3 col = vec3(0.); // background color vec3 hitPos = vec3(0); vec3 t = castRay(camPos, rayDir, hitPos); if(t.x > 0.0) { vec3 nor = calcNormal(hitPos); col = shading(hitPos, nor, rayDir, camPos); } //glow from the bottom vec3 bGlowColor = pal(syncs[0] * .075); // color change float bGlowDistance = 0.8; vec3 p = camPos + t.x * rayDir; vec3 bGlowLevel = bGlowColor * exp(-(p.y + 0.0) / bGlowDistance) * 9900.; col += bGlowLevel; col = clamp(mix(bGlowLevel, col, t.z), 0.0, 1.0); // distance fog + bass thunder float fogAmount = 0.01; col = col * exp(-t.x * fogAmount) + applyFog(col, t.x, rayDir, vec3(0., -0.5, 1.8), fogAmount) * (1.0 - exp(-t.x * fogAmount)); return col; } void main() { vec3 finalColor = render(getUV()); finalColor = postProcess(finalColor); o = vec4(finalColor, 1.); }