frag = () => `
precision highp float;
#define imax ${imax}
#define square_radius ${squareRadius}.
const float logLogRR = log2(log2(square_radius));
varying vec2 delta;
varying vec2 texcoord;
uniform vec2 rotator;
uniform vec2 size;
uniform vec2 pixelsize;
uniform float texsize;
uniform sampler2D orbittex;
vec4 unpackOrbit(int i) {
float fi = float(i);
vec2 texcoord = vec2(mod(fi, texsize), floor(fi / texsize)) / texsize;
return texture2D(orbittex, texcoord);
}
float interpolate(float s, float s1, float s2, float s3, float d) {
float d2 = d * d, d3 = d * d2;
return 0.5 * (s * (d3 - d2) + s1 * (d + 4.*d2 - 3.*d3) + s2 * (2. - 5.*d2 + 3.*d3) + s3 * (-d + 2.*d2 - d3));
}
struct result {
float time;
float zz;
float dzdz;
float stripe;
float argZ;
};
/* fractal calculator with perturbation theory for mandelbrot & julia set */
result calculator(vec2 AA) {
float u = delta.x + AA.x, v = delta.y + AA.y;
float zz, time, temp, du = 0., dv = 0.;
float stripe, s1, s2, s3;
vec2 z, dz, O, dO;
for (int i = 0; i < imax; i++) {
/* Recall global coordinates: Z = O + W, Z' = O' + W' */
vec4 values = unpackOrbit(i);
O = values.xy;
dO = values.zw;
z = O + vec2(u, v);
dz = dO + vec2(du, dv);
zz = dot(z, z);
/* Calc derivative: dW'(u,v) -> 2 * (O' * W + Z * W') */
temp = 2. * (dO.x * u - dO.y * v + z.x * du - z.y * dv);
dv = 2. * (dO.x * v + dO.y * u + z.x * dv + z.y * du);
du = temp;
/* Next step in the iterative process: W(u,v) -> W^2 + 2 * O * W + <delta> */
temp = u * u - v * v + 2. * (u * O.x - v * O.y);
v = u * v + u * v + 2. * (v * O.x + u * O.y);
u = temp;
u += delta.x;
v += delta.y;
/* Stripe average, a color algo based on statistcs */
stripe += z.x * z.y / zz * step(0.0, time);
s3 = s2; s2 = s1; s1 = stripe;
/* Loop in webgl1 */
time += 1.;
if (zz > square_radius) { break; }
}
time += clamp(1.0 + logLogRR - log2(log2(zz)), 0., 1.);
stripe = interpolate(stripe, s1, s2, s3, fract(time));
return result(time, zz, dot(dz,dz), stripe, atan(z.y, z.x));
}
void main() {
/* Get result */
result R = calculator(vec2(0));
/* DEM (Distance Estimation) = 2 * |Z / Z'| * ln(|Z|) */
float dem = sqrt(R.zz / R.dzdz) * log2(R.zz);
float dem_weight = 800. / min(size.x, size.y);
/* Final coloring */
vec3 color;
color += 0.7 + 2.5 * (R.stripe / clamp(R.time, 0., 200.)) * (1. - 0.6 * step(float(imax), 1. + R.time));
color = 0.5 + 0.5 * sin(color + vec3(${colorA}, ${colorB}, ${colorC}) + 50.0 * R.time / float(imax));
gl_FragColor = vec4(color, 1.);
}`