radiance: margin inside the glass rim; haloed corona sparks and glints (oversized soft-falloff points)

This commit is contained in:
dangrubbb
2026-10-24 09:36:45 -04:00
parent aac2bdf2e6
commit fcc1326e86

View File

@ -98,7 +98,8 @@ float lifeAlpha(float x) {
float layerR(uint idx) { float layerR(uint idx) {
float k = h01(idx * 8u + 5u); float k = h01(idx * 8u + 5u);
float u = h01(idx * 8u + 4u); 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. // A drifting ridge field: density peaks along thin curved sheets, which cut the sphere as ribbons.
float density(vec3 dir, float t) { float density(vec3 dir, float t) {
@ -372,7 +373,7 @@ void main() {
} }
float r = length(pos); float r = length(pos);
vec3 n = pos / max(r, 1e-4); 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 // the cursor: the 2D fluid under the particle's screen position, pushed into 3D
vec3 bp = bodyToView(pos); vec3 bp = bodyToView(pos);
@ -403,7 +404,7 @@ void main() {
n = pos / max(r, 1e-4); n = pos / max(r, 1e-4);
vel -= n * max(dot(vel, n), 0.0) * smoothstep(rt - 0.05, rt + 0.01, r); 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)); 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)); stir = max(stir * exp(-uDt * 1.2), clamp(fm * front * 1.5, 0.0, 1.5));
oPos = vec4(pos, stir); oPos = vec4(pos, stir);
@ -425,6 +426,7 @@ uniform float uR; // css px
uniform float uDpr; uniform float uDpr;
out vec4 vColor; out vec4 vColor;
out float vGlow; out float vGlow;
out float vCore;
void main() { void main() {
uint idx = uint(gl_VertexID); 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); 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); 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); 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 // 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) // (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.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); col.a *= lifeAlpha(lt);
// stirred particles heat up: brighter, hotter, a little bigger // 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.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)); col.a = min(1.0, col.a * (1.0 + stir * 0.5));
size *= 1.0 + stir * 0.8; size *= 1.0 + stir * 0.5;
vGlow = max(vGlow, clamp(stir * 0.8, 0.0, 1.0)); vGlow = max(vGlow, clamp(stir * 0.2, 0.0, 0.25));
} else { } else {
P p = corona(idx); P p = corona(idx);
vec2 disp = s0.xy; vec2 disp = s0.xy;
@ -491,7 +493,10 @@ void main() {
vec2 px = uCenter + vec2(vp.x, -vp.y) * uR; 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_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; vColor = col;
} }
`; `;
@ -499,12 +504,12 @@ void main() {
const FRAG_PARTICLES = `${HEAD} const FRAG_PARTICLES = `${HEAD}
in vec4 vColor; in vec4 vColor;
in float vGlow; 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; out vec4 o;
void main() { void main() {
vec2 c = gl_PointCoord - 0.5; float rr = length(gl_PointCoord - 0.5) * 2.0; // 0 at the centre, 1 at the edge of the point
float r = length(c); float core = 1.0 - smoothstep(0.36 * vCore, vCore, rr);
float core = smoothstep(0.5, 0.18, r); float halo = vGlow * pow(max(1.0 - rr, 0.0), 2.2) * 0.55;
float halo = vGlow * smoothstep(0.5, 0.0, r) * 0.55;
float a = vColor.a * clamp(core + halo, 0.0, 1.0); float a = vColor.a * clamp(core + halo, 0.0, 1.0);
if (a < 0.01) discard; if (a < 0.01) discard;
o = vec4(vColor.rgb * a, a); o = vec4(vColor.rgb * a, a);