main
frag 99 lines 3.23 KB
Raw
1 #version 460 core
2 precision highp float;
3
4 #include <flutter/runtime_effect.glsl>
5
6 // Uniform layout (must match the order .setFloat() is called in Dart):
7 // 0-1: uSize (vec2)
8 // 2: uTime
9 // 3-5: uBaseColor (vec3, outer/base color of the orb)
10 // 6-8: uGlowColor (vec3, inner glow color)
11 uniform vec2 uSize;
12 uniform float uTime;
13 uniform vec3 uBaseColor;
14 uniform vec3 uGlowColor;
15
16 out vec4 fragColor;
17
18 // ---- Simplex noise (Ashima Arts, MIT licensed pattern) ----
19 vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
20 vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
21 vec3 permute(vec3 x) { return mod289(((x * 34.0) + 1.0) * x); }
22
23 float snoise(vec2 v) {
24 const vec4 C = vec4(0.211324865405187, 0.366025403784439,
25 -0.577350269189626, 0.024390243902439);
26 vec2 i = floor(v + dot(v, C.yy));
27 vec2 x0 = v - i + dot(i, C.xx);
28 vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
29 vec4 x12 = x0.xyxy + C.xxzz;
30 x12.xy -= i1;
31 i = mod289(i);
32 vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))
33 + i.x + vec3(0.0, i1.x, 1.0));
34 vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);
35 m = m * m;
36 m = m * m;
37 vec3 x = 2.0 * fract(p * C.www) - 1.0;
38 vec3 h = abs(x) - 0.5;
39 vec3 ox = floor(x + 0.5);
40 vec3 a0 = x - ox;
41 m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
42 vec3 g;
43 g.x = a0.x * x0.x + h.x * x0.y;
44 g.yz = a0.yz * x12.xz + h.yz * x12.yw;
45 return 130.0 * dot(m, g);
46 }
47
48 float fbm(vec2 p) {
49 float v = 0.0;
50 float amp = 0.5;
51 for (int i = 0; i < 5; i++) {
52 v += amp * snoise(p);
53 p *= 2.0;
54 amp *= 0.5;
55 }
56 return v;
57 }
58
59 void main() {
60 vec2 fragCoord = FlutterFragCoord().xy;
61 vec2 center = uSize * 0.5;
62 float radiusPx = min(uSize.x, uSize.y) * 0.36;
63 vec2 uv = (fragCoord - center) / radiusPx;
64 float dist = length(uv);
65
66 // soft circular falloff -> matches the blurred edge in the reference image
67 float sphereMask = 1.0 - smoothstep(0.75, 1.05, dist);
68
69 // gentle breathing pulse for the inner glow size
70 float breathe = 0.5 + 0.5 * sin(uTime * 0.6);
71
72 // slowly rotate coordinates to drive the swirling highlight bands
73 float angle = uTime * 0.15;
74 float ca = cos(angle);
75 float sa = sin(angle);
76 vec2 ruv = vec2(uv.x * ca - uv.y * sa, uv.x * sa + uv.y * ca);
77
78 // thin swirl streaks (stretched fbm), drifting over time
79 float streaks = fbm(vec2(ruv.x * 2.0, ruv.y * 6.0) + vec2(uTime * 0.05, 0.0));
80 streaks = smoothstep(0.1, 0.9, streaks);
81
82 // inner core glow, offset slightly like the reference, pulsing + drifting
83 vec2 glowCenter = vec2(-0.15, 0.25) + 0.05 * vec2(cos(uTime * 0.3), sin(uTime * 0.4));
84 float glowDist = length(uv - glowCenter);
85 float innerGlow = exp(-glowDist * glowDist * (2.5 - 0.4 * breathe));
86
87 // base radial gradient: outer base color -> inner glow color
88 vec3 color = mix(uBaseColor, uGlowColor, innerGlow);
89
90 // subtle rotating light streaks near the rim
91 float rim = smoothstep(0.55, 1.0, dist) * (1.0 - smoothstep(0.95, 1.05, dist));
92 color += streaks * rim * 0.35;
93
94 // soft white wash toward the edges, matching the blurred-glass look
95 color = mix(color, vec3(1.0), smoothstep(0.5, 1.05, dist) * 0.6);
96
97 float alpha = sphereMask;
98 fragColor = vec4(color * alpha, alpha);
99 }