#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 layout(location = 600) uniform vec3 shapes[15]; // shapes - x = horizontal position, y = vertical position, z = length layout(location = 700) uniform vec3 test; // shapes test //layout(binding = 1) uniform sampler2D u_hexGridTex; //uniform sampler2D u_fft_texture; layout(binding = 0) uniform sampler2D u_ShapesTex; // uniform sampler2D shapes texture // float u_time = syncs[0]; vec3 palette(float t){ vec3 a=vec3(0.46,0.2,0.94); vec3 b=vec3(0.66,0.64,0.77); vec3 c=vec3(0.91,0.62,0.97); vec3 d=vec3(0.26,0.2,0.84); return a+b*cos(6.28318*(c*t+d)); } vec2 getUV() { 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); } ///////////////// // 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 sdSphere(vec3 p, float r) { return length(p) - r; } 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 length(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 opU( float d1, float d2 ) { return -max( -d1, -d2 ); } vec2 mapScene(in vec3 p) { float res = p.y; float mat = 0.; float hexRadius = 0.85; vec3 hexpos = vec3(p.x, p.y - 2.5, p.z); HexData hex = hexTile(hexpos, 1.5); float distFromCenter = hexDistance(hex.axial); int fftIndex = int(clamp(distFromCenter + 1.0, 0.0, 511.0)); float fftVal = fft_output[fftIndex]; float hexHeight = 1.0 + fftVal * 4.0; // Rotate individual hex tiles if needed vec3 r = hex.local; // r.yz *= rot2D(PI * 0.5); r.xz *= rot2D(0.5); //float d1 = hexPylon(vec3(r.x, (r.y + hexHeight / 2), r.z), vec2(hexRadius, hexHeight / 2)); float d1 = hexPylon(vec3(r.x, r.y, r.z), vec2(hexRadius, hexHeight)); res = (d1 < res) ? d1 : res; /* const float gridSize = 16.; for(float j = 0.; j < gridSize; j++) { for(float i = 0.; i < gridSize; i++) { ivec2 texSize = textureSize(u_ShapesTex, 0); vec2 texCoord = (vec2(i, j)) / vec2(texSize); vec4 shapeData = texture(u_ShapesTex, texCoord); // RGBA: x, y, length, active float shapeActive = shapeData.a; if(shapeActive < 0.5) continue; vec3 shapePos = p - vec3(-70.0 + (shapeData.x * 2.), 12. + (shapeData.y * 80.), 0.0); float a = sdSphere(shapePos, 0.8); res = min(res, a); if(res == a) { mat = 1.0; } } }*/ return vec2(res, mat); } //////////////// // RAYCAST // //////////////// vec3 castRay(vec3 ro, vec3 rd, inout vec3 pos) { float mat = 0.; float hit = 0.; float t = 0.; vec2 res; // Raymarching for(int i = 0; i < 20; i++) { pos = ro + rd * t; res = mapScene(pos); // Get distance to objects, x = dist, y = material mat = res.y; t += res.x; // "march" the ray // if(abs(t) < tolerance * (t * 0.0125 + 1.0)) { if(abs(res.x) < 0.0001) { hit = 1.; break; } if(t > 200) break; } 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 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 normalize(n); } vec3 addPointLight(vec3 lightPos, vec3 lightColor, float intensity, vec3 worldPos, vec3 viewDir, vec3 normal, float roughness) { // Light vector from surface to light 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; } float getAmbientOcc(vec3 p, vec3 n) { float occ = 0.; float weight = 1.; for(int i = 0; i < 8; i++) { float len = 0.01 + 0.02 * float(i * i); float dist = mapScene(p + n * len).x; occ += (len - dist) * weight; weight *= 0.85; } return 1.0 - clamp(0.6 * occ, 0., 1.); } vec3 applyFog(vec3 col, float t, vec3 rd, vec3 lightDir, float fogAmount) { float syncsBass = clamp((syncs[1] + syncs[2] + syncs[3]), 0., 1.); float fogAmount2 = 1.0 - exp(-t * fogAmount); float sunAmount = max(dot(rd, lightDir), 0.0); // highlight color vec3 fogColor = mix(vec3(0.2706, 0.2706, 0.2863), vec3(0.2314, 0.2314, 0.2314), // Main color pow(sunAmount, syncsBass * 1.0)); return mix(col, fogColor, fogAmount2); } // Point light with no shadow and radius based falloff vec3 addPointLightNoShadow(vec3 lightPos, vec3 lightColor, float intensity, float radius, vec3 worldPos, vec3 viewDir, vec3 normal, float roughness) { // Light vector from surface to light vec3 lightDir = lightPos - worldPos; float lightDistance = length(lightDir); lightDir = normalize(lightDir); // Attenuation (radius based falloff) float attenuation = clamp(intensity - lightDistance * lightDistance / (radius * radius), 0.0, 1.0); // 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; } /*vec3 addPointLight(vec3 lightPos, vec3 lightColor, float intensity, vec3 worldPos, vec3 viewDir, vec3 normal) { vec3 lightDir = normalize(lightPos - worldPos); float lightDistance = length(lightPos - worldPos); // Attenuation float attenuation = intensity / (1.0 + 0.1 * lightDistance + 0.01 * lightDistance * lightDistance); // Diffuse float NdotL = max(dot(normal, lightDir), 0.0); // Specular (Blinn-Phong) vec3 halfDir = normalize(lightDir - viewDir); float NdotH = max(dot(normal, halfDir), 0.0); float specular = pow(NdotH, 32.0); // Shadow float shadow = softshadow(worldPos + normal * 0.01, lightDir, 0.01, lightDistance, 8.0); return lightColor * (NdotL + specular * 0.5) * attenuation * shadow; } */ vec3 shading(vec3 p, vec3 n, vec3 dir, float material) { float shininess = 0.01; vec3 outMaterial = vec3(0.); if(material == 0.) { outMaterial = vec3(0.4941, 0.4941, 0.4941); shininess = 0.6; } else if(material == 1.) { outMaterial = vec3(0.6196, 0.6118, 0.6118); shininess = .7; } else if(material == 2.) { outMaterial = vec3(0.3255, 0.4784, 0.3255); shininess = .2; } else if(material == 3.) { outMaterial = vec3(0.2471, 0.3059, 0.6314); shininess = 1.0; } else if(material == 4.) { outMaterial = vec3(0.9961, 1.0, 0.9922); shininess = .1; } else if(material == 5.) { outMaterial = vec3(0.9961, 1.0, 0.9922); shininess = .3; } vec3 lights = vec3(0.); lights += addPointLight(vec3(0., 20.0, 10.), vec3(0.77, 0.26, 0.73), 15.0, p, dir, n, shininess); lights += addPointLight(vec3(-10., 20.0, -10.), vec3(0.18, 0.61, 0.86), 15., p, dir, n, shininess); // LIGHTS IN HEX GRID PATTERN /* float gridsize = 16.0; // or GRID if you want full size vec3 p = vec3(0.); for(float j = 0.; j < gridsize; j++) { for(float i = 0.; i < gridsize; i++) { ivec2 texSize = textureSize(u_hexGridTex, 0); vec2 texCoord = (vec2(i, j)) / vec2(texSize); vec4 hexData = texture(u_hexGridTex, texCoord); // RGBA: x, y, z, dist vec3 hexPos = hexData.rgb; float hexDist = hexData.a; // Optionally use hexDist for ripple effect with FFT int index = clamp(int((hexDist / 34.)*512.), 0, 511); float hexSize = getScaledFFT(index, 15. ,0.); //float a = sdHex(p - hexPos, 1.0 + hexSize, 0.0); lights += addPointLightNoShadow(vec3(hexPos.x, (hexPos.y + hexSize) + 2., hexPos.z), palette(hexSize* 1.5), clamp(hexSize * 5., 0., 1.), 3.4 ,v, dir, n, shininess); } } */ vec3 lightDir = vec3(0., 2., 3); //float sun_dif = clamp(dot(n, lightDir), 0., 1.); //float shadow = softshadow(v + n * 0.01, lightDir, .01, 30., 18.); //lights += vec3(0.6431, 0.7804, 0.8588) * sun_dif * shadow * occ; float ind = clamp(dot(n, normalize(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.75; 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(0.4545)); // 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 = normalize(camTarget - camPos), r = normalize(cross(vec3(0, 1, 0), f)), u = cross(f, r), c = f * fov, i = c + uv.x * r + uv.y * u, d = normalize(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, t.y); } //glow from the bottom vec3 bGlowColor = palette(syncs[0] * .5); // color change float bGlowDistance = 0.3; 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.); } /* vec3 render2(vec2 uv, float time) { vec3 res = vec3(.0); float pos = syncs[5]; if (uv.x >= pos && uv.x <= pos+0.01 ) { res += vec3(1.); } //if (uv.x >= 0.0 && uv.x <= 0.01 ) { // res += vec3(abs(syncs[4]*2)); //} //res += vec3(0.1, 0.2, 0.3) * abs(syncs[2]*1.2); return res; } void main() { vec2 uv = gl_FragCoord.xy * 2. / vec2(1920,1080); vec3 col = render2(uv, u_time); o = vec4(col,1.0); } */