Public
Edited
Apr 23, 2023
16 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
gpuAccumulate = regl({
vert: `
precision highp float;
attribute float n;
attribute float presets;
uniform mat3 view3;
uniform float colorSpeed, colorPhase, pointSize, sqrtBatchSize, colorSign;
uniform vec2 offset;
varying vec3 color;
#define PI ${Math.PI}

struct Mobius {
vec2 a, b, c, d;
};

struct IFS {
Mobius a, b, c; // can we not make arrays?
};

IFS skull = IFS( Mobius( vec2(0.4866733034189119,-0.3457824044206985), vec2(1.313262575615668,-1.397026140339055), vec2(0.6516350951229584,1.638719823441038), vec2(-1.8569883564943233,0.08818231772017304)), Mobius( vec2(0.5795578225793658,1.3549839078686818), vec2(-1.8961028244298554,1.6087998022720393), vec2(-1.6882600255129114,0.3069160294563704), vec2(0.0036256316221829365,-2.0331095041409233) ), Mobius( vec2(0.31508558391625563,1.0498951917336012), vec2(-0.7344985142475648,-0.9506556944928284), vec2(-1.288507550763319,-0.5351060846302649), vec2(-1.5200243034970713,0.21087848965428035) ) );

IFS stars = IFS( Mobius( vec2(1.496509486320491,-0.5973510559562649), vec2(1.363031770057287,0.5030253265047588), vec2(-0.4006162540899725,-0.31598846100639305), vec2(0.3877012648959322,-1.1534511520185347)), Mobius( vec2(0.37948263847029284,1.0729183770897013), vec2(-1.6818327845132162,-1.5667178744100405), vec2(-0.6804687668035543,-1.8026611211435384), vec2(0.18355448066088614,1.1028015889392742)), Mobius( vec2(-0.5482198806114792,1.0682003658572363), vec2(0.1303466381970876,-0.924249479448636), vec2(0.06475305759483793,-0.6112945687883007), vec2(1.130285084727879,-1.554137395983805)));

IFS dragon = IFS( Mobius( vec2(-1.5049655316774313,-1.0046110176648915), vec2(0.6950357700194231,-0.432217929539951), vec2(1.0743308469633628,0.6074866445391349), vec2(-1.4504110751965176,1.084841058616748)), Mobius( vec2(0.8879006445000018,0.1631992819881769), vec2(1.8187741523098753,1.4747701825935757), vec2(0.9488978374634134,0.7531535508928877), vec2(0.2046657793807769,-2.1349204141857965)), Mobius( vec2(0.6810830544856391,0.41883146175194397), vec2(-1.247827026913857,1.3800558371943485), vec2(1.2236590009001986,0.5638551016962444), vec2(-1.9784761192044398,-0.8425079666566594)));

IFS gasket = IFS( Mobius( vec2(-0.1018252798481565,-1.6993659680125772), vec2(1.379590288668221,1.1523609868431468), vec2(0.4689151107386992,0.4121648021857115), vec2(1.7244514564858764,-1.4367706357328038)), Mobius( vec2(-0.7373058434565494,-0.08334095212148668), vec2(-1.6491235833287208,0.9879685699677004), vec2(-0.09822345862515205,-0.7683141638693157), vec2(-0.9538636622332818,-0.4259876509291862)), Mobius( vec2(-1.022065959402516,0.2559407944576475), vec2(1.6979795385246752,-0.501974961351221), vec2(1.410013313430138,-1.2657227272429628), vec2(1.0331107145329936,-0.25404098701767536)));

IFS horsehead = IFS( Mobius( vec2(-0.620175038921428,1.3486543214753421), vec2(-0.1484539805952454,-0.44787716345703377), vec2(0.16257288894496202,1.8122404157983816), vec2(-0.3222155161945405,0.9625246056492645) ), Mobius( vec2(-0.7583961504085504,-1.3767091668206852), vec2(-0.9072365341139186,-0.9145698171667607), vec2(1.0177899842219502,1.347423640986904), vec2(0.4915774405750364,-1.7247189839909915) ), Mobius( vec2(-1.962175731310627,-0.7706747774053593), vec2(-1.3333358846582626,-1.5350176212096804), vec2(1.5549725520690356,0.32891254004323117), vec2(-1.3882946360470316,-1.8181413285838781) ) );

IFS ifs = stars; // choose your preset here

vec2 mul_complex( vec2 a, vec2 b ) {
return vec2( a.x * b.x - a.y * b.y, a.y * b.x + a.x * b.y );
}

vec2 div_complex( vec2 a, vec2 b ) {
float len2_b = b.x * b.x + b.y * b.y;
return vec2( ( a.x * b.x + a.y * b.y ) / len2_b, ( a.y * b.x - a.x * b.y ) / len2_b );
}

vec2 add( vec2 a, vec2 b ) {
return vec2( a.x + b.x, a.y + b.y );
}

vec2 mobius_on_point( vec2 a, vec2 b, vec2 c, vec2 d, vec2 xy ) {
return div_complex( add( mul_complex( a, xy ), b ), add( mul_complex( c, xy ), d ) );
}

float rand(vec2 co) {
return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
}

vec2 iterate (vec2 xy, out float branch_value) {
branch_value = rand(xy + branch_value); // is there a better way to make randomness?
Mobius mobius;
if( branch_value < 0.333 ) { mobius = ifs.a; }
else if( branch_value < 0.666 ) { mobius = ifs.b; }
else { mobius = ifs.c; }
return mobius_on_point( mobius.a, mobius.b, mobius.c, mobius.d, xy );
}

vec3 colorscale (float t) {
return 0.5 + 0.5 * vec3(
cos((2.0 * PI) * t - colorPhase),
cos((2.0 * PI) * (t - 1.0 / 3.0) - colorPhase),
cos((2.0 * PI) * (t - 2.0 / 3.0) - colorPhase)
);
}

void main () {
vec2 p = 4.0 * vec2(mod(n, sqrtBatchSize), floor(n / sqrtBatchSize)) / sqrtBatchSize + offset;
float smoothed_branch_value = 0.5;
float branch_value;
for (int i = 0; i < ${iterations}; i++) {
p = iterate(p, branch_value);
smoothed_branch_value = smoothed_branch_value * 0.9 + branch_value * 0.1;
}

// smoothed_branch_value tells us the last transforms used, and allows color speed and phase to be applied
color = colorscale(smoothed_branch_value * colorSpeed * colorSign);

vec2 xy = (view3 * vec3(p, 1)).xy;
gl_Position = vec4(xy, 0, 1);
gl_PointSize = pointSize;
}`,
frag: `
precision lowp float;
varying vec3 color;
uniform highp float pointSize;
void main () {
gl_FragColor = vec4(1, color) / (pointSize * pointSize);
}`,
attributes: {
n: randobuffer
},
uniforms: {
offset: () => [Math.random() * 2 - 1, Math.random() * 2 - 1],
colorSpeed: regl.prop("colorSpeed"),
colorPhase: regl.prop("colorPhase"),
pointSize: regl.prop("pointSize"),
colorSign: regl.prop("colorSign"),
sqrtBatchSize: Math.floor(Math.sqrt(batchSize))
},
blend: {
enable: true,
func: {
srcRGB: 1,
srcAlpha: 1,
dstRGB: 1,
dstAlpha: 1
},
equation: {
rgb: "add",
alpha: "add"
}
},
framebuffer: regl.prop("dst"),
primitive: "points",
depth: { enable: false },
count: batchSize
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more