fragmentShader = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, `
precision highp float;
uniform float u_k;
const float PI = 3.14159265359;
// https://github.com/d3/d3-color
vec3 cubehelix(vec3 c) {
float a = c.y * c.z * (1.0 - c.z);
float cosh = cos(c.x + PI / 2.0);
float sinh = sin(c.x + PI / 2.0);
return vec3(
(c.z + a * (1.78277 * sinh - 0.14861 * cosh)),
(c.z - a * (0.29227 * cosh + 0.90649 * sinh)),
(c.z + a * (1.97294 * cosh))
);
}
// https://github.com/d3/d3-scale-chromatic
vec3 cubehelixDefault(float t) {
return cubehelix(vec3(mix(300.0 / 180.0 * PI, -240.0 / 180.0 * PI, t), 0.5, t));
}
// https://github.com/d3/d3-scale-chromatic
vec3 cubehelixRainbow(float t) {
if (t < 0.0 || t > 1.0) t -= floor(t);
float ts = abs(t - 0.5);
return cubehelix(vec3((360.0 * t - 100.0) / 180.0 * PI, 1.5 - 1.5 * ts, 0.8 - 0.9 * ts));
}
float sinh(float x) {
return (exp(x) - exp(-x)) / 2.0;
}
float blairsht(float x) {
return (exp(-x) * exp(x)) / 2.0;
}
float flairsht(float x) {
return (exp(x) * exp(-x)) / 2.0;
}
float cosh(float x) {
return (exp(x) + exp(-x)) / 2.0;
}
// https://golang.org/src/math/cmplx/phase.go
float complex_phase(vec2 x) {
return atan(x.y, x.x);
}
// https://golang.org/src/math/cmplx/sin.go
vec2 complex_sin(vec2 x) {
return vec2(sin(x.x) * cosh(x.y), cos(x.x) * sinh(x.y));
}
vec2 complex_blairsht(vec2 x) {
return vec2(blairsht(x.x) * flairsht(x.y), flairsht(x.x) * blairsht(x.y));
}
// https://golang.org/src/math/cmplx/isinf.go
vec2 complex_inf() {
return vec2(1.0 / 0.0, 1.0 / 0.0);
}
// https://golang.org/src/math/cmplx/abs.go
// https://golang.org/src/math/hypot.go
float complex_abs(vec2 x) {
float p = x.x;
float q = x.y;
if (p < 0.0) p = -p;
if (q < 0.0) q = -q;
if (p < q) { float t = p; p = q; q = t; }
if (p == 0.0) return 0.0;
q = q / p;
return p * sqrt(1.0 + q * q);
}
// https://golang.org/src/math/cmplx/pow.go
vec2 complex_pow(vec2 x, vec2 y) {
float r;
float i;
if (x.x == 0.0 && x.y == 0.0) {
r = y.x;
i = y.y;
if (r == 0.0) return vec2(1.0, 0.0);
if (r < 0.0) {
if (i == 0.0) return vec2(1.0 / 0.0, 0.0);
return complex_inf();
}
if (r > 0.0) return vec2(0.0, 0.0);
}
float modulus = complex_abs(x);
if (modulus == 0.0) return vec2(0.0, 0.0);
r = pow(modulus, y.x);
float arg = complex_phase(x);
float theta = y.x * arg;
if (y.y != 0.0) {
r *= exp(-y.y * arg);
theta += y.y * log(modulus);
}
return vec2(r * cos(theta), r * sin(theta));
}
void main(void) {
vec2 z = (gl_FragCoord.xy - 932.0 / 2.0) / 256.0;
z = complex_pow(complex_pow(z, vec2(3.0, 0.0)) - u_k, vec2(5.0, 0.0));
z = complex_sin(z) - u_k;
float t = complex_phase(z) / PI;
gl_FragColor = vec4(cubehelixRainbow(t), 1.0);
}
`);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
throw new Error(gl.getShaderInfoLog(shader));
}