Whirlpool (precision-stable)
Left to run, the whirlpool slowly turns grainy and chunky,
worst near the center. That isn’t in the design — the iTime term adds a
uniform angular offset, so the vortex should spin rigidly without ever
changing detail. The decay is a numerical artifact:
iTime * 0.3grows without bound, socos=/=sinlose precision in their fractional argument as the magnitude climbs.step(0.5, sw)is a hard, un-antialiased edge, so any coordinate error gets thresholded into a full pixel flip — and the quadrant boundaries pack tightest near the center, where the speckle shows first.
Two changes fix it, shown here via #+attr_diff as a changeset from the
whirlpool — wrap the time angle so cos=/=sin never see a large argument,
and swap step for an fwidth-scaled smoothstep so precision noise no longer
flips whole pixels:
Diff: whirlpool-shader → whirlpool-stable-shader
--- whirlpool-shader
+++ whirlpool-stable-shader
@@ -1,20 +1,23 @@
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy; // <0,1>
vec2 p = uv - 0.5; // recenter so the swirl pivots on the middle
float r = length(p); // distance from the center
float a = atan(p.y, p.x); // current angle
- // twist harder near the center, and let it flow slowly over time
- a += 6.0 * exp(-3.0 * r) + iTime * 0.3;
+ // twist harder near the center; wrap the time term to one full turn so
+ // cos/sin never see a large argument (one revolution looks identical)
+ a += 6.0 * exp(-3.0 * r) + mod(iTime * 0.3, 6.2831853);
// rebuild swirled coordinates back in <0,1>
vec2 sw = vec2(cos(a), sin(a)) * r + 0.5;
vec3 col = vec3(0); // start with black
- col = vec3(step(0.5, sw), 0); // same quadrant step, now on the whirlpool
+ vec2 aa = fwidth(sw); // pixel footprint of the swirled coords
+ vec2 e = smoothstep(0.5 - aa, 0.5 + aa, sw); // antialiased quadrant edge
+ col = vec3(e, 0); // same quadrants, now without the speckle
// Output to screen
fragColor = vec4(col,1.0);
}
|
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy; // <0,1>
vec2 p = uv - 0.5; // recenter so the swirl pivots on the middle
float r = length(p); // distance from the center
float a = atan(p.y, p.x); // current angle
// twist harder near the center, and let it flow slowly over time
a += 6.0 * exp(-3.0 * r) + iTime * 0.3;
// rebuild swirled coordinates back in <0,1>
vec2 sw = vec2(cos(a), sin(a)) * r + 0.5;
vec3 col = vec3(0); // start with black
col = vec3(step(0.5, sw), 0); // same quadrant step, now on the whirlpool
// Output to screen
fragColor = vec4(col,1.0);
}