diff --git a/src/scripts/orb.js b/src/scripts/orb.js index cc4d029..ba88366 100644 --- a/src/scripts/orb.js +++ b/src/scripts/orb.js @@ -98,7 +98,8 @@ float lifeAlpha(float x) { float layerR(uint idx) { float k = h01(idx * 8u + 5u); float u = h01(idx * 8u + 4u); - return k < 0.5 ? mix(0.94, 1.0, u) : mix(0.4, 0.94, u); + // both stay clear of the glass at r = 1, leaving a margin around the rim + return k < 0.5 ? mix(0.86, 0.925, u) : mix(0.4, 0.85, u); } // A drifting ridge field: density peaks along thin curved sheets, which cut the sphere as ribbons. float density(vec3 dir, float t) { @@ -372,7 +373,7 @@ void main() { } float r = length(pos); vec3 n = pos / max(r, 1e-4); - float surf = step(0.9, rt); + float surf = step(0.855, rt); // the cursor: the 2D fluid under the particle's screen position, pushed into 3D vec3 bp = bodyToView(pos); @@ -403,7 +404,7 @@ void main() { n = pos / max(r, 1e-4); vel -= n * max(dot(vel, n), 0.0) * smoothstep(rt - 0.05, rt + 0.01, r); r = mix(r, rt, 1.0 - exp(-uDt * 1.6)); - pos = n * min(r, 0.985); + pos = n * min(r, 0.93); stir = max(stir * exp(-uDt * 1.2), clamp(fm * front * 1.5, 0.0, 1.5)); oPos = vec4(pos, stir); @@ -425,6 +426,7 @@ uniform float uR; // css px uniform float uDpr; out vec4 vColor; out float vGlow; +out float vCore; void main() { uint idx = uint(gl_VertexID); @@ -458,17 +460,17 @@ void main() { size = mix(1.5 + r.y * 1.5 + n * 1.3, 2.8 + r.w * 2.4, spark); float tw = 0.5 + 0.5 * sin(t * (1.2 + r.x * 2.5) + r.w * 40.0); col.a *= mix(1.0, mix(0.4, 1.0, tw), spark); - vGlow = spark; + vGlow = spark * 0.5; // the far side reads dimmer through the glass, and so do particles hanging deep in the volume // (it also thins the crowd that edge-on particles would form along the limb) col.a *= mix(0.2, 1.0, smoothstep(-0.2, 0.6, bp.z)); - col.a *= mix(0.65, 1.0, step(0.9, rt)); + col.a *= mix(0.65, 1.0, step(0.855, rt)); col.a *= lifeAlpha(lt); // stirred particles heat up: brighter, hotter, a little bigger col.rgb = mix(col.rgb, vec3(1.0, 0.8, 0.55), clamp(stir * 0.3, 0.0, 0.4)); col.a = min(1.0, col.a * (1.0 + stir * 0.5)); - size *= 1.0 + stir * 0.8; - vGlow = max(vGlow, clamp(stir * 0.8, 0.0, 1.0)); + size *= 1.0 + stir * 0.5; + vGlow = max(vGlow, clamp(stir * 0.2, 0.0, 0.25)); } else { P p = corona(idx); vec2 disp = s0.xy; @@ -491,7 +493,10 @@ void main() { vec2 px = uCenter + vec2(vp.x, -vp.y) * uR; gl_Position = vec4(px.x / uView.x * 2.0 - 1.0, 1.0 - px.y / uView.y * 2.0, 0.0, 1.0); - gl_PointSize = size * sc * uDpr * persp; + // glowing points are drawn larger so the halo has room around the core + float glowScale = 1.0 + vGlow * 2.4; + gl_PointSize = size * sc * uDpr * persp * glowScale; + vCore = 1.0 / glowScale; vColor = col; } `; @@ -499,12 +504,12 @@ void main() { const FRAG_PARTICLES = `${HEAD} in vec4 vColor; in float vGlow; +in float vCore; // the core's share of the point's width; the rest is room for the halo out vec4 o; void main() { - vec2 c = gl_PointCoord - 0.5; - float r = length(c); - float core = smoothstep(0.5, 0.18, r); - float halo = vGlow * smoothstep(0.5, 0.0, r) * 0.55; + float rr = length(gl_PointCoord - 0.5) * 2.0; // 0 at the centre, 1 at the edge of the point + float core = 1.0 - smoothstep(0.36 * vCore, vCore, rr); + float halo = vGlow * pow(max(1.0 - rr, 0.0), 2.2) * 0.55; float a = vColor.a * clamp(core + halo, 0.0, 1.0); if (a < 0.01) discard; o = vec4(vColor.rgb * a, a);