#version 300 es #define E (2.71828182846) #define pi (3.14159265358979323844) #define NUM_OCTAVES (4) precision highp float; struct ColoredSDF { float distance; vec4 color; }; struct SDFArgs { vec2 st; float amount; float duration; float time; float mainRadius; }; float triangle(float t, float p) { return 2.0 * abs(t / p - floor(t / p + 0.5)); } float spring(float t, float d) { return 1.0 - exp(-E * 2.0 * t) * cos((1.0 - d) * 115.0 * t); } float silkySmooth(float t, float k) { return atan(k * sin((t - 0.5) * pi)) / atan(k) * 0.5 + 0.5; } float scaled(float edge0, float edge1, float x) { return clamp((x - edge0) / (edge1 - edge0), float(0), float(1)); } float fixedSpring(float t, float d) { float s = mix( 1.0 - exp(-E * 2.0 * t) * cos((1.0 - d) * 115.0 * t), 1.0, scaled(0.0, 1.0, t) ); return s * (1.0 - t) + t; } float bounce(float t, float d) { return -sin(pi * (1.0 - d) * t) * (1.0 - t) * exp(-2.71828182846 * 2.0 * t) * t * 10.0; } float random(vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123); } float random(ivec2 st) { return random(vec2(st)); } float random(float p) { return random(vec2(p)); } float opSmoothUnion(float d1, float d2, float k) { if (k <= 0.0) { k = 0.000001; } float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0); return mix(d2, d1, h) - k * h * (1.0 - h); } float opSmoothSubtraction(float d1, float d2, float k) { if (k <= 0.0) { k = 0.000001; } float h = clamp(0.5 - 0.5 * (d2 + d1) / k, 0.0, 1.0); return mix(d2, -d1, h) + k * h * (1.0 - h); } float opSmoothIntersection(float d1, float d2, float k) { if (k <= 0.0) { k = 0.000001; } float h = clamp(0.5 - 0.5 * (d2 - d1) / k, 0.0, 1.0); return mix(d2, d1, h) + k * h * (1.0 - h); } float sdRoundedBox(vec2 p, vec2 b, vec4 r) { r.xy = p.x > 0.0 ? r.xy : r.zw; r.x = p.y > 0.0 ? r.x : r.y; vec2 q = abs(p) - b + r.x; return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r.x; } float sdSegment(vec2 p, vec2 a, vec2 b) { vec2 pa = p - a; vec2 ba = b - a; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); return length(pa - ba * h); } float sdArc(vec2 p, vec2 sca, vec2 scb, float ra, float rb) { p *= mat2(sca.x, sca.y, -sca.y, sca.x); p.x = abs(p.x); return scb.y * p.x > scb.x * p.y ? length(p - ra * scb) - rb : abs(length(p) - ra) - rb; } float arc(vec2 st, float startAngle, float length, float radius, float width) { return sdArc( st, vec2(sin(startAngle), cos(startAngle)), vec2(sin(length), cos(length)), radius, width ); } vec2 rotate(vec2 v, float a) { float s = sin(a); float c = cos(a); mat2 m = mat2(c, s, -s, c); return m * v; } vec3 blendLinearBurn_13_5(vec3 base, vec3 blend) { return max(base + blend - vec3(1.0), vec3(0.0)); } vec3 blendLinearBurn_13_5(vec3 base, vec3 blend, float opacity) { return blendLinearBurn_13_5(base, blend) * opacity + base * (1.0 - opacity); } float blendScreen_21_19(float base, float blend) { return 1.0 - (1.0 - base) * (1.0 - blend); } vec3 blendScreen_21_19(vec3 base, vec3 blend) { return vec3( blendScreen_21_19(base.r, blend.r), blendScreen_21_19(base.g, blend.g), blendScreen_21_19(base.b, blend.b) ); } vec3 blendScreen_21_19(vec3 base, vec3 blend, float opacity) { return blendScreen_21_19(base, blend) * opacity + base * (1.0 - opacity); } vec4 permute(vec4 x) { return mod((x * 34.0 + 1.0) * x, 289.0); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } vec3 fade(vec3 t) { return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); } float cnoise(vec3 P) { vec3 Pi0 = floor(P); vec3 Pi1 = Pi0 + vec3(1.0); Pi0 = mod(Pi0, 289.0); Pi1 = mod(Pi1, 289.0); vec3 Pf0 = fract(P); vec3 Pf1 = Pf0 - vec3(1.0); vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec4 iy = vec4(Pi0.yy, Pi1.yy); vec4 iz0 = vec4(Pi0.z); vec4 iz1 = vec4(Pi1.z); vec4 ixy = permute(permute(ix) + iy); vec4 ixy0 = permute(ixy + iz0); vec4 ixy1 = permute(ixy + iz1); vec4 gx0 = ixy0 / 7.0; vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5; gx0 = fract(gx0); vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); vec4 sz0 = step(gz0, vec4(0.0)); gx0 -= sz0 * (step(vec4(0.0), gx0) - 0.5); gy0 -= sz0 * (step(vec4(0.0), gy0) - 0.5); vec4 gx1 = ixy1 / 7.0; vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5; gx1 = fract(gx1); vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); vec4 sz1 = step(gz1, vec4(0.0)); gx1 -= sz1 * (step(vec4(0.0), gx1) - 0.5); gy1 -= sz1 * (step(vec4(0.0), gy1) - 0.5); vec3 g000 = vec3(gx0.x, gy0.x, gz0.x); vec3 g100 = vec3(gx0.y, gy0.y, gz0.y); vec3 g010 = vec3(gx0.z, gy0.z, gz0.z); vec3 g110 = vec3(gx0.w, gy0.w, gz0.w); vec3 g001 = vec3(gx1.x, gy1.x, gz1.x); vec3 g101 = vec3(gx1.y, gy1.y, gz1.y); vec3 g011 = vec3(gx1.z, gy1.z, gz1.z); vec3 g111 = vec3(gx1.w, gy1.w, gz1.w); vec4 norm0 = taylorInvSqrt( vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)) ); g000 *= norm0.x; g010 *= norm0.y; g100 *= norm0.z; g110 *= norm0.w; vec4 norm1 = taylorInvSqrt( vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)) ); g001 *= norm1.x; g011 *= norm1.y; g101 *= norm1.z; g111 *= norm1.w; float n000 = dot(g000, Pf0); float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); float n111 = dot(g111, Pf1); vec3 fade_xyz = fade(Pf0); vec4 n_z = mix( vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z ); vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); return 2.2 * n_xyz; } float rand(vec2 n) { return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453); } float noise(vec2 p) { vec2 ip = floor(p); vec2 u = fract(p); u = u * u * (3.0 - 2.0 * u); float res = mix( mix(rand(ip), rand(ip + vec2(1.0, 0.0)), u.x), mix(rand(ip + vec2(0.0, 1.0)), rand(ip + vec2(1.0, 1.0)), u.x), u.y ); return res * res; } float fbm(vec2 x) { float v = 0.0; float a = 0.5; vec2 shift = vec2(100.0); mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.5)); for (int i = 0; i < NUM_OCTAVES; ++i) { v += a * noise(x); x = rot * x * 2.0 + shift; a *= 0.5; } return v; } #define HASHSCALE1 (0.1031) #define HASHSCALE3 (vec3(0.1031, 0.103, 0.0973)) #define HASHSCALE4 (vec3(0.1031, 0.103, 0.0973, 0.1099)) float Hash11(float p) { vec3 p3 = fract(vec3(p) * HASHSCALE1); p3 += dot(p3, p3.yzx + 19.19); return fract((p3.x + p3.y) * p3.z); } vec2 Hash22(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * HASHSCALE3); p3 += dot(p3, p3.yzx + 19.19); return fract((p3.xx + p3.yz) * p3.zy); } vec2 Rand22(vec2 co) { float x = fract(sin(dot(co.xy, vec2(122.9898, 783.233))) * 43758.5453); float y = fract(sin(dot(co.xy, vec2(457.6537, 537.2793))) * 37573.5913); return vec2(x, y); } vec3 SnowSingleLayer( vec2 uv, float layer, vec2 speed, vec4 uCumulativeAudio, float uTime ) { uv = uv * (1.5 + layer); float size = 0.01; float xOffset = uv.y * (((Hash11(layer) * 2.0 - 1.0) * 0.5 + 1.0) * speed.x) + sin( layer * 2963.0 + uCumulativeAudio.y * 0.05625 + uCumulativeAudio.z * 0.075 ); float yOffset = speed.y + uTime * 1.75 + uCumulativeAudio.x * 0.07125 + cos(uTime) * 0.1; xOffset += sin(uTime * 2.0 + uv.x + layer * 2938.0) * 0.25; uv += vec2(xOffset, yOffset); vec2 rgrid = Hash22(floor(uv) + 31.1759 * layer); uv = fract(uv); uv -= (rgrid * 2.0 - 1.0) * 0.35; uv -= 0.5; float r = length(uv); float circleSize = 0.05 * (1.0 + 0.2 * sin(uTime * size + layer)); float val = smoothstep(circleSize, -circleSize, r); val = smoothstep(0.0, 0.2, val); vec3 col = vec3(val, val, val) * rgrid.x; return col; } /** * End new code for colored orb */ ColoredSDF applyIdleState( ColoredSDF sdf, SDFArgs args, bool isDarkMode /** * new bool */ ) { float midRadius = 0.12; float maxRadius = 0.3; float t1 = 1.0; float gamma = 3.0; float omega = pi / 2.0; float k = exp(-gamma) * omega; float radius; if (args.time <= t1) { float t_prime = args.time / t1; float springValue = 1.0 - exp(-gamma * t_prime) * cos(omega * t_prime); radius = midRadius * springValue; } else { float adjustedTime = args.time - t1; radius = midRadius + (maxRadius - midRadius) * (1.0 - exp(-k * adjustedTime)); } float distance = length(args.st) - radius; sdf.distance = mix(sdf.distance, distance, args.amount); float alpha = sin(pi / 0.7 * args.time) * 0.3 + 0.7; vec4 color = vec4(isDarkMode ? vec3(1.0) : vec3(0.0), alpha); sdf.color = mix(sdf.color, color, args.amount); return sdf; } ColoredSDF applyIdleStateLegacy(ColoredSDF sdf, SDFArgs args, bool isDarkMode) { float connectedLinearAnimation = scaled(0.0, 2.0, args.duration); float connectedAnimation = fixedSpring(connectedLinearAnimation, 0.96); float circleSize = mix( pow(scaled(0.0, 3.0, args.time), 2.0) * 0.75 + 0.1, 1.0, connectedAnimation ) * 0.33; vec2 rotatedCoords = rotate( args.st, -args.time * pi - connectedAnimation * pi * 2.0 - pi * 2.0 * 5.0 * silkySmooth(scaled(0.0, 5.0, args.time), 2.0) ); float strokeWidth = mix(circleSize / 2.0, circleSize, connectedAnimation); float connecting = abs(length(args.st) - circleSize) - strokeWidth; float connected = length(args.st) - circleSize; float idleDist = mix(connecting, connected, connectedAnimation); float d = min(sdf.distance, idleDist); sdf.distance = mix(sdf.distance, d, args.amount); float angle = atan(rotatedCoords.y, rotatedCoords.x); float alpha = mix( min(1.0, scaled(-pi, pi, angle)), 1.0, connectedLinearAnimation ); float spinningCircleDist = length( rotatedCoords - vec2(-mix(circleSize, strokeWidth, connectedAnimation), 0.0) ) - strokeWidth; alpha = min( 1.0, max( alpha, smoothstep(0.005, 0.0, spinningCircleDist) + connectedAnimation * 4.0 ) ); sdf.color = mix( sdf.color, vec4(isDarkMode ? vec3(1.0) : vec3(0.0), alpha), args.amount ); return sdf; } ColoredSDF applyListenState( ColoredSDF sdf, SDFArgs args, float micLevel, float listenTimestamp, /* new */ float touchDownTimestamp, /* new */ float touchUpTimestamp, /* new */ bool fadeBloopWhileListening /* new */ ) { float breathingSequence = sin(args.time) * 0.5 + 0.5; float entryAnimation = fixedSpring(scaled(0.0, 3.0, args.duration), 0.9); float touch = fixedSpring(scaled(0.0, 1.0, args.time - touchDownTimestamp), 0.99) - fixedSpring(scaled(0.0, 0.8, args.time - touchUpTimestamp), 1.0); float listenAnimation = clamp( spring(scaled(0.0, 0.9, args.duration), 1.0), 0.0, 1.0 ); float radius = 0.0; float smoothlevel = micLevel; float l1 = smoothlevel; radius = 0.38 + l1 * 0.05 + breathingSequence * 0.03; radius *= 1.0 - (1.0 - entryAnimation) * 0.25; float ring = 10000.0; if (touch > 0.0) { touch = min(touch, listenAnimation); float arcWidth = radius * 0.1; radius -= touch * arcWidth * 2.3; radius = min( radius, mix(radius, args.mainRadius - arcWidth * 2.3 - l1 * 0.01, touch) ); float startAngle = 0.0; float arcLengthTouch = smoothstep(0.04, 1.0, touch) * pi * (1.0 - arcWidth / 3.0 / radius); float arcLength = 0.0; float radiusTouch = radius * fixedSpring(scaled(0.0, 1.0, args.duration), 1.0) * args.amount + l1 * 0.01; radiusTouch += arcWidth * 1.3 * mix(-1.0, 1.0, smoothstep(0.0, 0.12, touch)); float ringRadius = 0.0; arcLength = arcLengthTouch; ringRadius = radiusTouch; startAngle = pi / 2.0 - (args.time - touchDownTimestamp) / 2.0; ring = arc(args.st, startAngle, arcLength, ringRadius, arcWidth); } float d = length(args.st) - radius; d = min(d, ring); sdf.distance = mix(sdf.distance, d, args.amount); if (fadeBloopWhileListening) { sdf.color.a = mix( sdf.color.a, mix(1.0, 1.0 - l1 * 0.6, listenAnimation), args.amount ); } else { sdf.color.a = 1.0; } return sdf; } ColoredSDF applyThinkState(ColoredSDF sdf, SDFArgs args) { float d = 1000.0; int count = 5; float entryAnimation = spring(scaled(0.0, 1.0, args.duration), 1.0); float thinkingDotEntryAnimation = spring( scaled(0.1, 1.1, args.duration), 1.0 ); float thinkingDotRadius = mix(0.2, 0.06, thinkingDotEntryAnimation) * args.amount; args.st.x -= thinkingDotRadius * 0.5 * thinkingDotEntryAnimation; for (int i = 0; i < count; i++) { float f = float(float(i) + 0.5) / float(count); float a = -f * pi * 2.0 + args.time / 3.0 + spring(scaled(0.0, 10.0, args.duration), 1.0) * pi / 2.0; float ringRadi = args.mainRadius * 0.45 * entryAnimation; ringRadi -= (sin( entryAnimation * pi * 4.0 + a * pi * 2.0 + args.time * 3.0 - silkySmooth(args.time / 4.0, 2.0) * pi * 1.0 ) * 0.5 + 0.5) * args.mainRadius * 0.1; vec2 pos = vec2(cos(a), sin(a)) * ringRadi; float dd = length(args.st - pos) - args.mainRadius * 0.5; d = opSmoothUnion( d, dd, 0.03 * scaled(0.0, 10.0, args.duration) + 0.8 * (1.0 - entryAnimation) ); float dotAngle = f * pi * 2.0; float dotRingRadius = (sin( thinkingDotEntryAnimation * pi * 4.0 + a * pi * 2.0 + args.time * 0.1 * pi * 4.0 ) * 0.5 + 0.5) * thinkingDotRadius * 0.3; vec2 dotPos = vec2(-args.mainRadius, args.mainRadius) * 0.8 * thinkingDotEntryAnimation; vec2 dotOffset = vec2(cos(dotAngle + args.time), sin(dotAngle + args.time)) * dotRingRadius; float dotD = length(args.st - dotPos - dotOffset) - thinkingDotRadius * 0.8; d = opSmoothUnion( d, dotD, (1.0 - min(thinkingDotEntryAnimation, args.amount)) * thinkingDotRadius ); } sdf.distance = mix(sdf.distance, d, args.amount); sdf.color.a = 1.0; return sdf; } ColoredSDF applySpeakState( ColoredSDF sdf, SDFArgs args, vec4 avgMag, float silenceAmount, float silenceDuration ) { float d = 1000.0; int barCount = 4; for (int i = 0; i < barCount; i++) { float f = float(float(i) + 0.5) / float(barCount); float w = 1.0 / float(barCount) * 0.44; float h = w; float wave = sin(f * pi * 0.8 + args.time) * 0.5 + 0.5; float entryAnimation = spring( scaled(0.1 + wave * 0.4, 1.0 + wave * 0.4, args.duration), 0.98 ); vec2 pos = vec2(f - 0.5, 0.0) * args.mainRadius * 1.9; pos.y = 0.25 * (1.0 - entryAnimation); if (silenceAmount > 0.0) { float bounceStagger = f / 5.0; float bounceDelay = 0.6; float bounceTimer = scaled( bounceDelay, bounceDelay + 1.0, fract((silenceDuration + bounceStagger) / 2.0) * 2.0 ); pos.y += bounce(bounceTimer, 6.0) * w * 0.25 * silenceAmount * pow(entryAnimation, 4.0) * pow(args.amount, 4.0); } h += avgMag[i] * (0.1 + (1.0 - abs(f - 0.5) * 2.0) * 0.1); float dd = sdRoundedBox(args.st - pos, vec2(w, h), vec4(w)); d = opSmoothUnion(d, dd, 0.2 * (1.0 - args.amount)); } sdf.distance = mix(sdf.distance, d, args.amount); sdf.color.a = 1.0; return sdf; } ColoredSDF applyListenAndSpeakState( ColoredSDF sdf, SDFArgs args, float micLevel, vec4 avgMag, vec4 cumulativeAudio, int binCount, vec3 bloopColorMain, vec3 bloopColorLow, vec3 bloopColorMid, vec3 bloopColorHigh, sampler2D uTextureNoise, bool listening, bool isAdvancedBloop, float xmassMode ) { float entryAnimation = fixedSpring(scaled(0.0, 2.0, args.duration), 0.92); float radius = (listening ? 0.37 : 0.43) * (1.0 - (1.0 - entryAnimation) * 0.25) + micLevel * 0.065; float maxDisplacement = 0.01; float oscillationPeriod = 4.0; float displacementOffset = maxDisplacement * sin(2.0 * pi / oscillationPeriod * args.time); vec2 adjusted_st = args.st - vec2(0.0, displacementOffset); if (!isAdvancedBloop) { sdf.color = mix(sdf.color, vec4(bloopColorMain, 1.0), args.amount); sdf.distance = mix(sdf.distance, length(adjusted_st) - radius, args.amount); return sdf; } vec4 uAudioAverage = avgMag; vec4 uCumulativeAudio = cumulativeAudio; float scaleFactor = 1.0 / (2.0 * radius); vec2 uv = adjusted_st * scaleFactor + 0.5; uv.y = 1.0 - uv.y; vec3 color; float noiseScale = 1.25; float windSpeed = 0.075; float warpPower = 0.19; float waterColorNoiseScale = 18.0; float waterColorNoiseStrength = 0.01; float textureNoiseScale = 1.0; float textureNoiseStrength = 0.08; float verticalOffset = 0.09; float waveSpread = 1.0; float layer1Amplitude = 1.0; float layer1Frequency = 1.0; float layer2Amplitude = 1.0; float layer2Frequency = 1.0; float layer3Amplitude = 1.0; float layer3Frequency = 1.0; float fbmStrength = 1.0; float fbmPowerDamping = 0.55; float overallSoundScale = 1.0; float blurRadius = 1.0; float timescale = 1.0; float time = args.time * timescale * 0.85; noiseScale = mix(1.25, 2.0, xmassMode); waterColorNoiseStrength = mix(0.01, 0.005, xmassMode); textureNoiseStrength = mix(0.03, 0.01, xmassMode); blurRadius = mix(0.9, 0.7, xmassMode); verticalOffset = mix(0.09, 0.0, xmassMode); layer1Amplitude = mix(1.0, 0.5, xmassMode); layer1Frequency = mix(1.0, 0.5, xmassMode); layer2Amplitude = mix(1.0, 0.5, xmassMode); layer2Frequency = mix(1.0, 0.5, xmassMode); layer3Amplitude = mix(1.0, 0.5, xmassMode); layer3Frequency = mix(1.0, 0.5, xmassMode); waveSpread = mix(1.0, 0.25, xmassMode); overallSoundScale = mix(1.0, 1.2, xmassMode); vec3 sinOffsets = vec3( uCumulativeAudio.x * 0.15 * overallSoundScale, -uCumulativeAudio.y * 0.5 * overallSoundScale, uCumulativeAudio.z * 1.5 * overallSoundScale ); verticalOffset += 1.0 - waveSpread; vec3 sinOffsetsXmass = vec3( uCumulativeAudio.x * 0.15 * overallSoundScale * 0.9, -uCumulativeAudio.y * 0.5 * overallSoundScale * 0.1875, uCumulativeAudio.z * 1.5 * overallSoundScale * 0.45 ); sinOffsets = mix(sinOffsets, sinOffsetsXmass, xmassMode); float noiseX = cnoise( vec3( uv * 1.0 + vec2(0.0, 74.8572), (time + uCumulativeAudio.x * 0.05 * overallSoundScale) * 0.3 ) ); float noiseY = cnoise( vec3( uv * 1.0 + vec2(203.91282, 10.0), (time + uCumulativeAudio.z * 0.05 * overallSoundScale) * 0.3 ) ); vec2 uvBis = uv + vec2(noiseX * 2.0, noiseY) * warpPower * 0.25; uv += vec2(noiseX * 2.0, noiseY) * warpPower; float noiseA = cnoise(vec3(uv * waterColorNoiseScale + vec2(344.91282, 0.0), time * 0.3)) + cnoise( vec3(uv * waterColorNoiseScale * 2.2 + vec2(723.937, 0.0), time * 0.4) ) * 0.5; uv += noiseA * waterColorNoiseStrength; uv.y -= verticalOffset; vec2 textureUv = uv * textureNoiseScale; float textureSampleR0 = texture(uTextureNoise, textureUv).r; float textureSampleG0 = texture( uTextureNoise, vec2(textureUv.x, 1.0 - textureUv.y) ).g; float textureNoiseDisp0 = mix( textureSampleR0 - 0.5, textureSampleG0 - 0.5, (sin(time + uCumulativeAudio.a * 2.0) + 1.0) * 0.5 ) * textureNoiseStrength; textureUv += vec2(63.861 + uCumulativeAudio.x * 0.05, 368.937); float textureSampleR1 = texture(uTextureNoise, textureUv).r; float textureSampleG1 = texture( uTextureNoise, vec2(textureUv.x, 1.0 - textureUv.y) ).g; float textureNoiseDisp1 = mix( textureSampleR1 - 0.5, textureSampleG1 - 0.5, (sin(time + uCumulativeAudio.a * 2.0) + 1.0) * 0.5 ) * textureNoiseStrength; textureUv += vec2(272.861, 829.937 + uCumulativeAudio.y * 0.1); textureUv += vec2(180.302 - uCumulativeAudio.z * 0.1, 819.871); float textureSampleR3 = texture(uTextureNoise, textureUv).r; float textureSampleG3 = texture( uTextureNoise, vec2(textureUv.x, 1.0 - textureUv.y) ).g; float textureNoiseDisp3 = mix( textureSampleR3 - 0.5, textureSampleG3 - 0.5, (sin(time + uCumulativeAudio.a * 2.0) + 1.0) * 0.5 ) * textureNoiseStrength; uv += textureNoiseDisp0; vec2 st = uv * noiseScale; vec2 q = vec2(0.0); q.x = fbm( st * 0.5 + windSpeed * (time + uCumulativeAudio.a * 0.175 * overallSoundScale) ); q.y = fbm( st * 0.5 + windSpeed * (time + uCumulativeAudio.x * 0.136 * overallSoundScale) ); vec2 r = vec2(0.0); r.x = fbm( st + 1.0 * q + vec2(0.3, 9.2) + 0.15 * (time + uCumulativeAudio.y * 0.234 * overallSoundScale) ); r.y = fbm( st + 1.0 * q + vec2(8.3, 0.8) + 0.126 * (time + uCumulativeAudio.z * 0.165 * overallSoundScale) ); float f = fbm(st + r - q); float fullFbm = (f + 0.6 * f * f + 0.7 * f + 0.5) * 0.5; fullFbm = pow(fullFbm, fbmPowerDamping); fullFbm *= fbmStrength; blurRadius = blurRadius * 1.5; vec2 snUv = (uv + vec2((fullFbm - 0.5) * 1.2) + vec2(0.0, 0.025) + textureNoiseDisp0) * vec2(layer1Frequency, 1.0); float sn = noise( snUv * 2.0 + vec2(sin(sinOffsets.x * 0.25), time * 0.5 + sinOffsets.x) ) * 2.0 * layer1Amplitude; float sn2 = smoothstep( sn - 1.2 * blurRadius, sn + 1.2 * blurRadius, (snUv.y - 0.5 * waveSpread) * (5.0 - uAudioAverage.x * 0.1 * overallSoundScale * 0.5) + 0.5 ); vec2 snUvBis = (uv + vec2((fullFbm - 0.5) * 0.85) + vec2(0.0, 0.025) + textureNoiseDisp1) * vec2(layer2Frequency, 1.0); float snBis = noise( snUvBis * 4.0 + vec2( sin(sinOffsets.y * 0.15) * 2.4 + 293.0, time * 1.0 + sinOffsets.y * 0.5 ) ) * 2.0 * layer2Amplitude; float sn2Bis = smoothstep( snBis - (0.9 + uAudioAverage.y * 0.4 * overallSoundScale) * blurRadius, snBis + (0.9 + uAudioAverage.y * 0.8 * overallSoundScale) * blurRadius, (snUvBis.y - 0.6 * waveSpread) * (5.0 - uAudioAverage.y * 0.75) + 0.5 ); vec2 snUvThird = (uv + vec2((fullFbm - 0.5) * 1.1) + textureNoiseDisp3) * vec2(layer3Frequency, 1.0); float snThird = noise( snUvThird * 6.0 + vec2( sin(sinOffsets.z * 0.1) * 2.4 + 153.0, time * 1.2 + sinOffsets.z * 0.8 ) ) * 2.0 * layer3Amplitude; float sn2Third = smoothstep( snThird - 0.7 * blurRadius, snThird + 0.7 * blurRadius, (snUvThird.y - 0.9 * waveSpread) * 6.0 + 0.5 ); sn2 = pow(sn2, 0.8); sn2Bis = pow(sn2Bis, 0.9); vec3 sinColor; sinColor = blendLinearBurn_13_5(bloopColorMain, bloopColorLow, 1.0 - sn2); sinColor = blendLinearBurn_13_5( sinColor, mix(bloopColorMain, bloopColorMid, 1.0 - sn2Bis), sn2 ); sinColor = mix( sinColor, mix(bloopColorMain, bloopColorHigh, 1.0 - sn2Third), sn2 * sn2Bis ); color = sinColor; float XSPEED = noise(vec2(time * 0.5, time * 0.1)) * 0.75; float YSPEED = cos(time + uCumulativeAudio.y * 0.05) * 0.75; vec2 wind = vec2(XSPEED, YSPEED); vec3 acc = vec3(0, 0, 0); for (float i = 0.0; i < 9.0; i++) { acc += SnowSingleLayer( uvBis, i * 0.85 + 0.75, wind, uCumulativeAudio, time ); } vec3 xmassColor; xmassColor = mix( vec3(0.004, 0.506, 0.996), vec3(0.973, 0.984, 1.0), 1.0 - sn2 ); xmassColor = mix( xmassColor, mix(vec3(0.004, 0.506, 0.996), vec3(1.0), 1.0 - sn2Bis), sn2 ); xmassColor = mix( xmassColor, mix(vec3(0.004, 0.506, 0.996), vec3(1.0), 1.0 - sn2Third), sn2 * sn2Bis ); xmassColor = mix(xmassColor, vec3(1.0), acc); color.rgb = mix(color, xmassColor, xmassMode); sdf.color = mix(sdf.color, vec4(color, 1), args.amount); sdf.distance = mix(sdf.distance, length(adjusted_st) - radius, args.amount); return sdf; } float micSdf(vec2 st, float muted) { float d = 100.0; float strokeWidth = 0.03; vec2 elementSize = vec2(0.12, 0.26); vec2 elementPos = vec2(0.0, elementSize.y * 0.585); float element = sdRoundedBox( st - elementPos, elementSize, vec4(min(elementSize.x, elementSize.y)) ); element = element - strokeWidth; d = min(d, element); vec2 standSize = elementSize * 2.2; vec2 standPos = vec2(elementPos.x, elementPos.y - 0.05); st.y += 0.08; float ta = -pi / 2.0; float tb = pi / 2.0; float w = 0.0; float stand = sdArc( st - standPos, vec2(sin(ta), cos(ta)), vec2(sin(tb), cos(tb)), standSize.x, w ); stand = min( stand, sdSegment(st - standPos, vec2(standSize.x, 0.06), vec2(standSize.x, 0.0)) ); stand = min( stand, sdSegment(st - standPos, vec2(-standSize.x, 0.06), vec2(-standSize.x, 0.0)) ); float foot = sdSegment( st - standPos, vec2(0.0, -standSize.x), vec2(0.0, -standSize.x * 1.66) ); foot = min( foot, sdSegment( st - standPos, vec2(-standSize.x * 0.68, -standSize.x * 1.66), vec2(standSize.x * 0.68, -standSize.x * 1.66) ) ); stand = min(stand, foot); d = min(d, abs(stand) - strokeWidth); return d; } ColoredSDF applyBottomAlignedBarsAndMicState( ColoredSDF sdf, SDFArgs args, vec4 avgMag, float micLevel, bool isDarkMode ) { float d = 1000.0; int barCount = 5; int loopCount = barCount; if (args.amount == 0.0) { loopCount = 1; } for (int i = 0; i < loopCount; i++) { float f = float(float(i) + 0.5) / float(barCount); float w = 1.0 / float(barCount) * 0.42; float h = w; float entryDuration = 1.8; float entryAnimation = fixedSpring(scaled(0.0, entryDuration, args.duration), 0.94) * args.amount; vec2 pos = vec2(f - 0.5, 0.0) * args.mainRadius * 1.9; pos.x *= entryAnimation; if (i == 0) { float micScale = mix(6.0 - micLevel * 2.0, 6.0, args.amount); float yOffset = w * 2.0; d = micSdf( (args.st - pos + vec2(-w * 0.15 * args.amount, yOffset)) * micScale, 1.0 - args.amount ) / micScale; } else { h += avgMag[i - 1] * (0.1 + (1.0 - abs(f - 0.5) * 2.0) * 0.1) * 0.7; h = mix(w, h, smoothstep(0.8, 1.0, entryAnimation)); float bubbleInDur = 0.5; float bubbleOutDur = 0.4; float bubbleEffect = fixedSpring( scaled( f / 4.0, f / 4.0 + bubbleInDur, args.duration - entryDuration / 8.0 ), 1.0 ) * pow( 1.0 - scaled( f / 8.0 + bubbleInDur / 8.0, f / 4.0 + bubbleInDur / 8.0 + bubbleOutDur, args.duration - entryDuration / 8.0 ), 2.0 ); h += bubbleEffect * min(h, w); w *= args.amount; h *= args.amount; h = min(h, 0.23); pos.y -= 0.25; pos.y += h; pos.y += bubbleEffect * w * 0.5; float dd = sdRoundedBox(args.st - pos, vec2(w, h), vec4(w)); d = min(d, dd); } } sdf.distance = d; sdf.color = mix( sdf.color, isDarkMode ? vec4(1.0) : vec4(0.0, 0.0, 0.0, 1.0), args.amount ); return sdf; } ColoredSDF applyHaltState(ColoredSDF sdf, SDFArgs args) { float radius = mix( 0.4, mix(0.4, 0.45, args.amount), sin(args.time * 0.25) * 0.5 + 0.5 ); float strokeWidth = mix(radius / 2.0, 0.02, args.amount); radius -= strokeWidth; radius *= mix(0.7, 1.0, args.amount); float circle = abs(length(args.st) - radius) - strokeWidth; sdf.distance = mix(sdf.distance, circle, args.amount); sdf.color.a = mix(sdf.color.a, pow(0.8, 2.2), scaled(0.5, 1.0, args.amount)); return sdf; } vec3 blendNormal(vec3 base, vec3 blend) { return blend; } vec3 blendNormal(vec3 base, vec3 blend, float opacity) { return blendNormal(base, blend) * opacity + base * (1.0 - opacity); } in vec2 out_uv; out vec4 fragColor; layout(std140) uniform BlorbUniformsObject { float time; float micLevel; float touchDownTimestamp; float touchUpTimestamp; float stateListen; float listenTimestamp; float stateThink; float thinkTimestamp; float stateSpeak; float speakTimestamp; float readyTimestamp; float stateHalt; float haltTimestamp; float stateFailedToConnect; float failedToConnectTimestamp; vec4 avgMag; vec4 cumulativeAudio; vec2 viewport; float screenScaleFactor; float silenceAmount; float silenceTimestamp; float xmassMode; bool isDarkMode; bool fadeBloopWhileListening; bool isNewBloop; bool isAdvancedBloop; vec3 bloopColorMain; vec3 bloopColorLow; vec3 bloopColorMid; vec3 bloopColorHigh; } ubo; uniform sampler2D uTextureNoise; void main() { vec2 st = out_uv - 0.5; float viewRatio = ubo.viewport.y / ubo.viewport.x; st.y *= viewRatio; ColoredSDF sdf; sdf.distance = 1000.0; sdf.color = vec4(1.0); SDFArgs args; args.st = st; args.time = ubo.time; args.mainRadius = 0.49; SDFArgs idleArgs = args; SDFArgs listenArgs = args; SDFArgs thinkArgs = args; SDFArgs speakArgs = args; SDFArgs haltArgs = args; SDFArgs failedToConnectArgs = args; idleArgs.amount = 1.0; listenArgs.amount = ubo.stateListen; thinkArgs.amount = ubo.stateThink; speakArgs.amount = ubo.stateSpeak; haltArgs.amount = ubo.stateHalt; failedToConnectArgs.amount = ubo.stateFailedToConnect; idleArgs.duration = ubo.time - ubo.readyTimestamp; listenArgs.duration = ubo.time - ubo.listenTimestamp; thinkArgs.duration = ubo.time - ubo.thinkTimestamp; speakArgs.duration = ubo.time - ubo.speakTimestamp; haltArgs.duration = ubo.time - ubo.haltTimestamp; failedToConnectArgs.duration = ubo.time - ubo.failedToConnectTimestamp; if (ubo.isNewBloop) { sdf = applyIdleState(sdf, idleArgs, ubo.isDarkMode); } else { sdf = applyIdleStateLegacy(sdf, idleArgs, ubo.isDarkMode); } if (failedToConnectArgs.amount > 0.0) { sdf = applyHaltState(sdf, failedToConnectArgs); } if (listenArgs.amount > 0.0) { if (ubo.isAdvancedBloop) { if (speakArgs.amount > 0.0) { listenArgs.amount = 1.0; } int binCount = 1; sdf = applyListenAndSpeakState( sdf, listenArgs, ubo.micLevel, ubo.avgMag, ubo.cumulativeAudio, binCount, ubo.bloopColorMain, ubo.bloopColorLow, ubo.bloopColorMid, ubo.bloopColorHigh, uTextureNoise, true, ubo.isAdvancedBloop, ubo.xmassMode ); } else { sdf = applyListenState( sdf, listenArgs, ubo.micLevel, ubo.listenTimestamp, ubo.touchDownTimestamp, ubo.touchUpTimestamp, ubo.fadeBloopWhileListening ); } } if (thinkArgs.amount > 0.0) { sdf = applyThinkState(sdf, thinkArgs); } if (speakArgs.amount > 0.0) { if (ubo.isAdvancedBloop) { int binCount = 1; sdf = applyListenAndSpeakState( sdf, speakArgs, ubo.micLevel, ubo.avgMag, ubo.cumulativeAudio, binCount, ubo.bloopColorMain, ubo.bloopColorLow, ubo.bloopColorMid, ubo.bloopColorHigh, uTextureNoise, false, ubo.isAdvancedBloop, ubo.xmassMode ); } else { float silenceDuration = ubo.time - ubo.silenceTimestamp; sdf = applySpeakState( sdf, speakArgs, ubo.avgMag, ubo.silenceAmount, silenceDuration ); } } if (haltArgs.amount > 0.0) { sdf = applyHaltState(sdf, haltArgs); } float clampingTolerance = 0.0075 / ubo.screenScaleFactor; float clampedShape = smoothstep(clampingTolerance, 0.0, sdf.distance); float alpha = sdf.color.a * clampedShape; if (!ubo.isNewBloop) { alpha *= scaled(0.0, 1.0, ubo.time); } fragColor = vec4(sdf.color.rgb * alpha, alpha); }