Rauzy Gasket
Iterates the barycentric algorithm to give an image of the Rauzy Gasket.
Source
image.glsl
// Rauzy gasket, drawn by iterating the fully subtractive algorithm on
// barycentric coordinates. A map fx/fy/fz applies when its coordinate
// dominates the other two (x > y + z etc.); points where some map always
// applies form the gasket and stay black. Points that reach the central hole
// (no map applies) are coloured by their position in the hole, dimmed by the
// number of steps taken to get there. The step budget grows as iTime^2, so
// the picture refines progressively as it runs.
const float r3 = 1.7320508075688772;
// Maps the central hole (all of x, y, z below the sum of the other two) back
// onto the whole triangle, giving coordinates to colour escaped points by.
const mat3 ex = mat3(1.,-1.,1.,1.,1.,-1.,-1.,1.,1.);
// Barycentric coordinates on the equilateral triangle with top vertex at
// (0,1); the top vertex is pure x, the lower left pure v, the lower right w.
vec3 cartToBary(vec2 p) {
float u = (1.0 + 2.0 * p.y) / 3.0;
float v = (1.0 - p.y - r3 * p.x) / 3.0;
float w = (1.0 - p.y + r3 * p.x) / 3.0;
return vec3(u, v, w);
}
// Barycentric -> Cartesian
vec2 baryToCart(vec3 b) {
float x = 0.5 * r3 * (b.z - b.y);
float y = b.x - 0.5 * (b.y + b.z);
return vec2(x, y);
}
// Fully subtractive maps: subtract the other two coordinates from one, then
// rescale by that coordinate's old value. Valid (all coordinates positive)
// exactly when the chosen coordinate dominates the other two.
vec3 fx(vec3 uv)
{
vec3 nv = uv;
nv.x = uv.x-uv.y-uv.z;
nv = nv/uv.x;
return nv;
}
vec3 fy(vec3 uv)
{
vec3 nv = uv;
nv.y = uv.y-uv.x-uv.z;
nv = nv/uv.y;
return nv;
}
vec3 fz(vec3 uv)
{
vec3 nv = uv;
nv.z = uv.z-uv.x-uv.y;
nv = nv/uv.z;
return nv;
}
float minV(vec3 uv)
{
return min(min(uv.x,uv.y),uv.z);
}
// Colours for the three vertex directions; cs pushes them past 1 so the
// mix stays bright after the depth dimming.
const float cs = 1.3;
const vec3 coly = cs*vec3(1.,0.,0.);
const vec3 colx = cs*vec3(1.,1.,1.);
const vec3 colz = cs*vec3(0.,0.,1.);
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy-vec2(.5,.5);
uv.x = uv.x*iResolution.x/iResolution.y;
uv=uv*1.65;
uv.y=uv.y+.25;
vec3 bary = cartToBary(uv);
vec4 col = vec4(0.,0.,0.,0.);
if(minV(bary) > 0.)
{
// Capped: by 256 iterations the point has converged or escaped at
// float precision, and an unbounded count grows GPU cost forever.
int steps = min(int(floor(iTime*iTime))+1, 256);
for(int i=0; i<steps; i++)
{
if(minV(fx(bary)) > 0.) { bary = fx(bary); }
else if(minV(fy(bary)) > 0.) { bary = fy(bary); }
else if(minV(fz(bary)) > 0.) { bary = fz(bary); }
else {
// Escaped into the central hole: colour by position in the
// hole, dimmed slowly with the escape depth i.
bary = ex*bary;
col = vec4((colx*bary.x+coly*bary.y+colz*bary.z)/(log(log(float(i+1))+1.)+1.), 1.);
break;
}
}
}
fragColor = col;
}