#version 410 core uniform float time; // в секундах uniform vec2 resolution; // разрешение экрана (в пикселях) uniform vec3 spectrum; // спектр: X=Низкие, Y=Средние, Z=Высокие uniform sampler2D pass_texture; // Предыдущий кадр #define iTime time #define PI 3.14159265359 layout(location = 0) out vec4 out_color; float hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123); } float hash(float n) { return fract(sin(n) * 43758.5453123); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); f = f * f * (3.0 - 2.0 * f); return mix(mix(hash(i + vec2(0.0, 0.0)), hash(i + vec2(1.0, 0.0)), f.x), mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), f.x), f.y); } float fbm(vec2 p) { float value = 0.0; float amplitude = 0.5; float frequency = 1.0; for (int i = 0; i < 4; i++) { value += amplitude * noise(p * frequency); frequency *= 2.0; amplitude *= 0.5; } return value; } mat2 rot(float a) { return mat2(cos(a), -sin(a), sin(a), cos(a)); } mat2 matrixRot(float a) { float c = cos(a), s = sin(a); return mat2(c, -s, s, c); } vec2 crtCurve(vec2 uv) { uv = uv * 2.0 - 1.0; vec2 distortion = vec2(0.12, 0.15); uv += uv * (uv.yx * uv.yx) * distortion; return uv * 0.5 + 0.5; } float drawLine(float dist, float thickness, float glowRadius) { float beam = smoothstep(thickness, 0.0, dist); float glow = smoothstep(glowRadius, 0.0, dist) * 0.5; return beam + glow; } float getGrid(vec2 uv, float bassMultiplier) { float perspective = 0.5 / (uv.y + 0.7); if (uv.y < -0.68) return 0.0; vec2 gridUV = vec2(uv.x * perspective, perspective + time * 1.5 + bassMultiplier * 0.8); float density = 4.0 + bassMultiplier * 2.0; vec2 lines = abs(fract(gridUV * density - 0.5) - 0.5) / (fwidth(gridUV) * density); float grid = 1.0 - min(lines.x, lines.y); float fade = smoothstep(-0.7, 0.2, uv.y); return clamp(grid, 0.0, 1.0) * fade * (0.2 + bassMultiplier * 0.3); } float matrixChar(vec2 st, float charId) { vec2 grid = floor(st * 4.0); if (grid.x < 0.0 || grid.x > 3.0 || grid.y < 0.0 || grid.y > 3.0) return 0.0; float h = hash(vec2(grid + charId * 13.0)); return step(0.5, h); } float map(vec3 p) { float bass = pow(spectrum.x, 1.5) * 4.0; float mids = pow(spectrum.y, 1.5) * 5.0; p.z -= time * 5.0; p.xy *= matrixRot(p.z * 0.12 + mids * 0.4); float a = atan(p.y, p.x); float r = length(p.xy); float tunnelRadius = 3.2 + bass * 1.2; float sectors = 6.0; float zRepeat = mod(p.z, 2.5) - 1.25; float dTunnel = tunnelRadius - r; dTunnel -= sin(a * sectors) * 0.4 * (1.0 - step(0.8, abs(zRepeat))); vec3 cPos = p; cPos.xy *= matrixRot(time * 0.3); cPos = mod(cPos, 5.0) - 2.5; float dCubes = length(max(abs(cPos) - vec3(0.3 + bass * 0.4), 0.0)); return min(dTunnel, dCubes); } // --- ШЕЙДЕР 1 --- vec3 renderShader1(vec2 fragCoord) { float bass = spectrum.x * 1.5; float mids = spectrum.y * 1.5; float highs = spectrum.z * 1.5; float volume = (bass + mids + highs) / 3.0; vec2 uvN = fragCoord / resolution.xy; uvN = crtCurve(uvN); if (uvN.x < 0.0 || uvN.x > 1.0 || uvN.y < 0.0 || uvN.y > 1.0) { return vec3(0.0); } float glitchLine = sin(uvN.y * 10.0 + time * 5.0) * sin(uvN.y * 3.0 - time * 10.0); float glitchThreshold = step(0.93 - highs * 0.1, hash(vec2(floor(time * 12.0), 1.0))); float xOffset = glitchLine * glitchThreshold * (0.015 + highs * 0.03); float blockY = floor(uvN.y * 25.0); float blockNoise = hash(vec2(blockY, floor(time * 16.0))); float tearTrigger = step(0.96 - (mids + highs) * 0.08, blockNoise); float tearOffset = (hash(vec2(blockY, 2.0)) - 0.5) * (0.08 + bass * 0.1) * tearTrigger; float totalXOffset = xOffset + tearOffset; float scanlines = sin(uvN.y * resolution.y * 1.5 + time * bass * 2.0) * (0.06 + bass * 0.02); vec2 glitchUV = uvN + vec2(totalXOffset, 0.0); vec2 uv = (glitchUV * 2.0 - 1.0) * (resolution / resolution.y); float perspective = 0.5 / (uv.y + 0.7); vec2 gridUV = vec2(uv.x * perspective, perspective - time * 0.8 - (bass * 0.5)); vec2 gridLines = abs(fract(gridUV - 0.5) - 0.5) / fwidth(gridUV); float lineFactor = min(gridLines.x, gridLines.y); float gridMask = 1.0 - min(lineFactor, 1.0); float gridIntensity = (0.02 + mids * 0.1 + bass * 0.2) * gridMask; gridIntensity *= smoothstep(-0.6, 0.4, uv.y); float sceneGray = 0.01 + gridIntensity; float baseRadius = 0.23 + bass * 0.12; float thickness = 0.012 + highs * 0.005; const int TRAIL_STEPS = 8; float trailIntensity = 0.06; float ringGlowTotal = 0.0; for (int i = 0; i < TRAIL_STEPS; i++) { float t = time - float(i) * trailIntensity; float ageFactor = float(i) / float(TRAIL_STEPS); float weight = 1.0 - ageFactor; vec2 distortedUV = uv; if (i > 0) { float distortStrength = ageFactor * (0.1 + mids * 0.3); distortedUV.x += sin(uv.y * 12.0 + t * 8.0) * distortStrength; distortedUV.y += cos(uv.x * 12.0 + t * 8.0) * distortStrength; } vec2 center = vec2(cos(t * 2.2 + volume) * 0.4, sin(t * 1.8 + volume) * 0.25); float radius = baseRadius + sin(t * 4.0) * 0.05; float dist = length(distortedUV - center); float distToRing = abs(dist - radius) - thickness; float glowSize = 0.02 + bass * 0.01; float glow = glowSize / max(distToRing, 0.001); glow *= weight; float ringBrightness = mix(0.75, 0.35 * (1.0 + mids), ageFactor); ringGlowTotal += ringBrightness * glow; } sceneGray += ringGlowTotal; sceneGray = 1.0 - exp(-sceneGray * 1.6); float finalGray = sceneGray * (1.0 + volume * 0.05); float noiseVal = (hash(uvN + time) - 0.5) * (0.04 + highs * 0.1); finalGray += noiseVal; finalGray -= scanlines; float vignette = uvN.x * uvN.y * (1.0 - uvN.x) * (1.0 - uvN.y); vignette = clamp(pow(16.0 * vignette, 0.35), 0.0, 1.0); finalGray *= vignette; float edgeCutoff = smoothstep(0.0, 0.01, uvN.x) * smoothstep(1.0, 0.99, uvN.x) * smoothstep(0.0, 0.01, uvN.y) * smoothstep(1.0, 0.99, uvN.y); finalGray *= edgeCutoff; finalGray = clamp(finalGray, 0.0, 1.0); finalGray = pow(finalGray, 1.4); finalGray = smoothstep(0.05, 0.95, finalGray); return vec3(finalGray); } // --- ШЕЙДЕР 2 --- vec3 renderShader2(vec2 fragCoord) { vec2 uv = (fragCoord * 2.0 - resolution.xy) / resolution.y; float bass = pow(spectrum.x, 1.5) * 4.0; float mids = pow(spectrum.y, 1.5) * 5.0; float highs = pow(spectrum.z, 1.5) * 6.0; vec2 centerUV = uv - vec2(0.0, 0.1); float radius = length(centerUV); float angle = atan(centerUV.y, centerUV.x); float grayScaleValue = 0.0; grayScaleValue = max(grayScaleValue, getGrid(uv, bass)); float baseRadius = 0.35 + sin(time * 2.0) * 0.05 + bass * 0.05; float wave = baseRadius + sin(angle * (10.0 + floor(bass)) + time * 6.0) * (mids * 0.15); wave += sin(angle * 180.0 - time * 40.0) * (highs * 0.025); float radarCircle = drawLine(abs(radius - wave), 0.005 + highs * 0.005, 0.03 + mids * 0.05); grayScaleValue = max(grayScaleValue, radarCircle); const int numMarkers = 32; float tails = 0.0; for (int j = 0; j < numMarkers; j++) { float markerAngle = (float(j) / float(numMarkers)) * 2.0 * PI; float angleDiff = abs(angle - markerAngle); if (angleDiff > PI) angleDiff = 2.0 * PI - angleDiff; float segmentAudio = mix(bass, mix(mids, highs, hash(float(j))), hash(float(j + 3))); float startRadius = wave; float endRadius = startRadius + 0.02 + segmentAudio * 0.65; if (radius >= startRadius && radius <= endRadius) { float beamWidth = 0.01 + highs * 0.005; float distToBeam = angleDiff * radius; float fadeAlongTail = 1.0 - smoothstep(startRadius, endRadius, radius); float phosphorGhost = 0.4 + 0.6 * sin(time * 8.0 - radius * 15.0 + float(j)); float beam = smoothstep(beamWidth, 0.0, distToBeam); float glow = smoothstep(beamWidth * 8.0, 0.0, distToBeam) * 0.6; tails += (beam + glow) * fadeAlongTail * phosphorGhost; } } grayScaleValue = max(grayScaleValue, tails); float screenAfterglow = smoothstep(0.8, 0.0, radius) * (bass * 0.2 + mids * 0.1); screenAfterglow *= 0.7 + 0.3 * sin(time * 12.0); grayScaleValue += screenAfterglow; float scanlines = sin(fragCoord.y * 1.5) * 0.2 + 0.8; grayScaleValue *= scanlines; float glitchTrigger = step(0.990 - highs * 0.015, hash(floor(uv.y * 40.0) + time * 5.0)); grayScaleValue += glitchTrigger * highs * 0.4; vec2 d = fragCoord / resolution.xy; float vignette = 0.1 + 0.9 * pow(16.0 * d.x * d.y * (1.0 - d.x) * (1.0 - d.y), 0.35); grayScaleValue *= vignette; return vec3(clamp(grayScaleValue, 0.0, 1.0)); } // --- ШЕЙДЕР 3 --- vec3 renderShader3(vec2 fragCoord) { vec2 uv = (fragCoord * 2.0 - resolution.xy) / min(resolution.x, resolution.y); vec2 screenUV = fragCoord / resolution.xy; float bass = clamp(spectrum.x, 0.0, 2.0); float mids = clamp(spectrum.y, 0.0, 2.0); float highs = clamp(spectrum.z, 0.0, 2.0); float currentRadius = length(uv); float currentFrame = 0.0; if (currentRadius >= 0.001) { vec2 dir = uv / currentRadius; float R = 0.35 + mids * 0.15; float r_wheel = 0.12 + mids * 0.1; float d = 0.20 + highs * 0.15; float k = R / r_wheel; float t_rot = time * (0.2 + mids * 0.4); float cosT = cos(t_rot), sinT = sin(t_rot); vec2 rotatedDir = vec2(dir.x * cosT - dir.y * sinT, dir.x * sinT + dir.y * cosT); float spiroX = (R + r_wheel) * rotatedDir.x - d * cos(k * (rotatedDir.x + time * 0.02)); float spiroY = (R + r_wheel) * rotatedDir.y - d * sin(k * (rotatedDir.y + time * 0.02)); float targetRadius = length(vec2(spiroX, spiroY)); vec2 noiseUV = uv * (8.0 + bass * 35.0) + vec2(time * 0.2, -time * 0.1); float fractalNoise = fbm(noiseUV) * (0.02 + bass * 0.3); targetRadius += fractalNoise; float dist = abs(currentRadius - targetRadius); float thickness = 0.003 + (mids * 0.01) + (fractalNoise * 0.05); float line = smoothstep(thickness, 0.0, dist); float glow = exp(-dist * (30.0 - highs * 15.0)) * 0.25; currentFrame = clamp(line + glow, 0.0, 1.0); } vec2 trailUV = (screenUV - 0.5) * (0.992 - bass * 0.005) + 0.5; vec3 prevFrameColor = texture(pass_texture, trailUV).rgb; float fadeRate = 0.91 + (highs * 0.04); fadeRate = clamp(fadeRate, 0.85, 0.97); vec3 finalColor = max(vec3(currentFrame), prevFrameColor * fadeRate); return smoothstep(0.02, 1.0, finalColor); } // --- ШЕЙДЕР 4 --- vec3 renderShader4(vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * resolution.xy) / resolution.y; float bass = pow(spectrum.x, 1.5) * 4.0; float highs = pow(spectrum.z, 1.5) * 6.0; float noiseSeed = time; float glitchTrigger = step(0.6, highs) * hash(vec2(floor(uv.y * 30.0), noiseSeed)); if (glitchTrigger > 0.7) { uv.x += (hash(vec2(uv.y, noiseSeed)) - 0.5) * 0.15 * highs; } vec3 ro = vec3(0.0, 0.0, 4.0); vec3 rd = normalize(vec3(uv, -1.2)); float d = 0.0, t = 0.0, maxDist = 35.0; for(int i = 0; i < 75; i++) { vec3 p = ro + rd * t; d = map(p); if(d < 0.001 || t > maxDist) break; t += d; } vec3 color = vec3(0.0); bool isBackground = (t >= maxDist); if(!isBackground) { float depth = 1.0 - (t / maxDist); float ao = float(75 - int(t * 2.2)) / 75.0; float rawLight = depth * ao; float noirEdge = smoothstep(0.3, 0.35, rawLight); color = vec3(noirEdge); color += vec3(smoothstep(0.1, 0.5, highs) * 0.4 * depth); } if (isBackground || color.r < 0.1) { vec2 matrixUV = fragCoord / 14.0; float colId = floor(matrixUV.x); float speed = (0.5 + hash(vec2(colId, 1.0)) * 0.5) * (time * 15.0 + highs * 20.0); matrixUV.y += speed; float rowId = floor(matrixUV.y); vec2 charSubUV = fract(matrixUV); float charId = hash(vec2(colId, rowId + floor(time * 10.0))); float glyph = matrixChar(charSubUV, charId); float trail = fract(-matrixUV.y / 20.0 + hash(vec2(colId, 4.0))); trail = smoothstep(0.1, 0.9, trail); float matrixIntensity = glyph * trail; if (isBackground) { color = vec3(matrixIntensity * 0.8); } else { color += vec3(matrixIntensity * 0.35); } } float grain = hash(fragCoord + noiseSeed); color += vec3(grain * (0.07 + highs * 0.22)); float scratch = step(0.996, hash(vec2(uv.x + floor(time * 12.0) * 0.1, 1.0))); color += vec3(scratch * 0.25 * hash(vec2(uv.y, noiseSeed))); float flicker = 1.0 - (hash(vec2(noiseSeed, 0.0)) * 0.12 * (1.0 + bass)); color *= flicker; color *= smoothstep(1.2, 0.4, length(uv)); return color; } ======================================== // переход 1 vec3 transitionAnalogStatic(vec2 fragCoord, float p, int nextShaderIdx) { float intensity = smoothstep(0.0, 0.5, p) * (1.0 - smoothstep(0.5, 1.0, p)); vec2 uvN = fragCoord / resolution.xy; vec2 distortedCoord = fragCoord; distortedCoord.x += (hash(vec2(floor(uvN.y * 30.0), time)) - 0.5) * resolution.x * 0.12 * intensity; distortedCoord.y += sin(time * 20.0) * resolution.y * 0.015 * intensity; vec3 colA = (nextShaderIdx == 2) ? renderShader1(distortedCoord) : renderShader2(distortedCoord); vec3 colB = (nextShaderIdx == 2) ? renderShader2(distortedCoord) : renderShader3(distortedCoord); vec3 mixedColor = mix(colA, colB, step(0.5, p)); float staticNoise = hash(fragCoord + time); mixedColor = mix(mixedColor, vec3(staticNoise), intensity * 0.85); float movingBar = sin(uvN.y * 3.0 - time * 5.0) * 0.5 + 0.5; mixedColor -= vec3(step(0.85, movingBar) * intensity * 0.4); return clamp(mixedColor, 0.0, 1.0); } // переход 2 vec3 transitionGlitchFlash(vec2 fragCoord, float p) { float intensity = smoothstep(0.0, 0.5, p) * (1.0 - smoothstep(0.5, 1.0, p)); vec2 uvN = fragCoord / resolution.xy; vec2 glitchCoord = fragCoord; float blockY = floor(uvN.y * 12.0); if (hash(vec2(blockY, floor(time * 15.0))) < intensity) { glitchCoord.x += (hash(vec2(blockY, time)) - 0.5) * resolution.x * 0.25; } vec3 col3 = renderShader3(glitchCoord); vec3 col4 = renderShader4(glitchCoord); vec3 mixedColor = mix(col3, col4, step(0.5, p)); vec3 flashColor = mixedColor + vec3(intensity * 1.6); if (intensity > 0.4 && hash(vec2(floor(time * 24.0), 1.0)) > 0.5) { flashColor = 1.0 - flashColor; } float slice = step(0.98 - intensity * 0.05, hash(vec2(uvN.y, time))); flashColor += vec3(slice * 0.6); return clamp(flashColor, 0.0, 1.0); } void main(void) { vec2 fragCoord = gl_FragCoord.xy; float currentBass = spectrum.x * 1.5; float currentMids = spectrum.y * 1.5; float currentHighs = spectrum.z * 1.5; float volume = (currentBass + currentMids + currentHighs) / 3.0; float duration = 420.0; float totalDuration = duration * 4.0; float localTime = mod(time, totalDuration); float blendTime = 2.0; vec3 finalColor = vec3(0.0); // Шейдер 1 -> Шейдер 2 if (localTime < duration) { if (localTime > duration - blendTime) { float progress = (localTime - (duration - blendTime)) / blendTime; finalColor = transitionAnalogStatic(fragCoord, progress, 2); } else { finalColor = renderShader1(fragCoord); } } // Шейдер 2 -> Шейдер 3 else if (localTime < duration * 2.0) { if (localTime > (duration * 2.0) - blendTime) { float progress = (localTime - ((duration * 2.0) - blendTime)) / blendTime; finalColor = transitionAnalogStatic(fragCoord, progress, 3); } else { finalColor = renderShader2(fragCoord); } } // Шейдер 3 -> Шейдер 4 else if (localTime < duration * 3.0) { if (localTime > (duration * 3.0) - blendTime) { float progress = (localTime - ((duration * 3.0) - blendTime)) / blendTime; finalColor = transitionGlitchFlash(fragCoord, progress); } else { finalColor = renderShader3(fragCoord); } } // Шейдер 4 -> Шейдер 1 else { if (localTime > totalDuration - blendTime) { float progress = (localTime - (totalDuration - blendTime)) / blendTime; finalColor = mix(renderShader4(fragCoord), renderShader1(fragCoord), progress); } else { finalColor = renderShader4(fragCoord); } } out_color = vec4(finalColor, 1.0); }