ChatGPT-Next-Web/app/shaders/fragment.glsl
2025-01-08 23:45:28 +08:00

1326 lines
32 KiB
GLSL

#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);
}