Published
Edited
Nov 26, 2019
2 forks
50 stars
Insert cell
Insert cell
Insert cell
viewof gl = {
const canvas = document.createElement("canvas");
canvas.width = width * devicePixelRatio;
canvas.height = height * devicePixelRatio;
canvas.style = `width: ${width}px; height: auto;`;
canvas.value = canvas.getContext("webgl");
return canvas;
}
Insert cell
init = {
gl.useProgram(program);
gl.enableVertexAttribArray(a_vertex);
gl.vertexAttribPointer(a_vertex, 2, gl.FLOAT, false, 0, 0);
gl.uniform2f(u_translate, viewof gl.width / 2, viewof gl.height / 2);
gl.viewport(0, 0, viewof gl.width, viewof gl.height);
}
Insert cell
draw = {
init;
gl.uniform1f(u_scale, Math.sin(now / 2000) * 2 + 10);
gl.uniform1f(u_t, now / 400 % (2 * Math.PI));
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
}
Insert cell
fragmentShader = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, `
precision highp float;

uniform sampler2D u_image;
uniform vec2 u_translate;
uniform float u_scale;
uniform float u_t;

const float c_pi = 3.14159265358979323846264;

vec4 color(float t) {
const float ar = 0.50, ag = 0.50, ab = 0.50;
const float br = 0.50, bg = 0.50, bb = 0.50;
const float cr = 1.00, cg = 1.00, cb = 1.00;
const float dr = 0.00, dg = 0.10, db = 0.20;
return vec4(
ar + br * cos(2.0 * c_pi * (cr * t + dr)),
ag + bg * cos(2.0 * c_pi * (cg * t + dg)),
ab + bb * cos(2.0 * c_pi * (cb * t + db)),
1.0
);
}

void main(void) {
const int n = ${N};
const float step = c_pi / float(n);
vec2 p = (gl_FragCoord.xy - u_translate) / u_scale;
float alpha;
for (int i = 0; i < n; i++) {
float theta = float(i) * step;
alpha += cos(cos(theta) * p.x + sin(theta) * p.y + u_t);
}
gl_FragColor = color(alpha * 2.0 / float(n));
}
`);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(shader));
return shader;
}
Insert cell
vertexShader = {
const shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, `
attribute vec2 a_vertex;

void main(void) {
gl_Position = vec4(a_vertex, 0.0, 1.0);
}
`);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(shader));
return shader;
}
Insert cell
vertexBuffer = {
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, Float32Array.of(-1, -1, +1, -1, +1, +1, -1, +1), gl.STATIC_DRAW);
return buffer;
}
Insert cell
program = {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw new Error(gl.getProgramInfoLog(program));
return program;
}
Insert cell
a_vertex = gl.getAttribLocation(program, "a_vertex")
Insert cell
u_translate = gl.getUniformLocation(program, "u_translate")
Insert cell
u_scale = gl.getUniformLocation(program, "u_scale")
Insert cell
u_t = gl.getUniformLocation(program, "u_t")
Insert cell
u_n = gl.getUniformLocation(program, "u_n")
Insert cell
height = 600
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