Published
Edited
Aug 31, 2019
1 fork
3 stars
Insert cell
Insert cell
Insert cell
viewof gl = {
const height = width;
const canvas = DOM.canvas(width * devicePixelRatio, height * devicePixelRatio);
canvas.style = `width: ${width}px; height: ${height}px`;
const gl = canvas.value = canvas.getContext("webgl", {antialias: false, depth: false, preserveDrawingBuffer: true});
gl.getExtension("OES_texture_float");
gl.blendFunc(gl.ONE, gl.ONE);
return canvas;
}
Insert cell
draw = {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.enableVertexAttribArray(timestepPosition);
gl.enableVertexAttribArray(renderPosition);
for (let i = 0; i < 64; ++i) {
gl.useProgram(timestepProgram);
gl.viewport(0, 0, K, K);
gl.disable(gl.BLEND);
if (i & 1) {
gl.bindFramebuffer(gl.FRAMEBUFFER, fb1);
gl.bindTexture(gl.TEXTURE_2D, t2);
} else {
gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
gl.bindTexture(gl.TEXTURE_2D, t1);
}
gl.bindBuffer(gl.ARRAY_BUFFER, qb);
gl.vertexAttribPointer(timestepPosition, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
if (i < 8) continue;
gl.useProgram(renderProgram);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.BLEND);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, ib);
gl.vertexAttribPointer(renderPosition, 2, gl.UNSIGNED_SHORT, false, 0, 0);
gl.drawArrays(gl.POINTS, 0, K * K);
yield;
}
}
Insert cell
timestepFragmentShader = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, `
precision mediump float;
uniform sampler2D u_image;
uniform vec2 u_size;
uniform float u_a;
uniform float u_b;
uniform float u_c;
uniform float u_d;
void main() {
vec2 v = texture2D(u_image, gl_FragCoord.xy / u_size).xy;
gl_FragColor = vec4(sin(u_a * v.y) - cos(u_b * v.x), sin(u_c * v.x) - cos(u_d * v.y), 0.0, 0.0);
}
`);
gl.compileShader(shader);
return shader;
}
Insert cell
timestepVertexShader = {
const shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
}
`);
gl.compileShader(shader);
return shader;
}
Insert cell
renderFragmentShader = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, `
void main() {
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.01);
}
`);
gl.compileShader(shader);
return shader;
}
Insert cell
renderVertexShader = {
const shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, `
uniform sampler2D u_image;
uniform vec2 u_size;
attribute vec2 a_position;
void main() {
gl_Position = vec4(texture2D(u_image, a_position / u_size).xy, 0.0, 2.0);
gl_PointSize = 1.0;
}
`);
gl.compileShader(shader);
return shader;
}
Insert cell
K = 512 * (devicePixelRatio > 1 ? 2 : 1)
Insert cell
qb = {
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return buffer;
}
Insert cell
ib = {
const array = new Uint16Array(2 * K * K);
for (let i = -1, y = 0; y < K; ++y) {
for (let x = 0; x < K; ++x) {
array[++i] = x;
array[++i] = y;
}
}
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return buffer;
}
Insert cell
a1 = {
const array = new Float32Array(4 * K * K);
for (let y = 0, i = 0; y < K; ++y) {
for (let x = 0; x < K; ++x, i += 4) {
array[i + 0] = Math.random();
array[i + 1] = Math.random();
}
}
return array;
}
Insert cell
t1 = {
settings; // Reinitialize on interaction.
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, K, K, 0, gl.RGBA, gl.FLOAT, a1);
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
}
Insert cell
t2 = {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, K, K, 0, gl.RGBA, gl.FLOAT, null);
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
}
Insert cell
fb1 = {
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, t1, 0);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return framebuffer;
}
Insert cell
fb2 = {
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, t2, 0);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return framebuffer;
}
Insert cell
renderProgram = {
const program = gl.createProgram();
gl.attachShader(program, renderVertexShader);
gl.attachShader(program, renderFragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.uniform2f(gl.getUniformLocation(program, "u_size"), K, K);
gl.useProgram(null);
return program;
}
Insert cell
renderPosition = gl.getAttribLocation(renderProgram, "a_position")
Insert cell
timestepProgram = {
const program = gl.createProgram();
gl.attachShader(program, timestepVertexShader);
gl.attachShader(program, timestepFragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.uniform2f(gl.getUniformLocation(program, "u_size"), K, K);
gl.uniform1f(gl.getUniformLocation(program, "u_a"), settings.a);
gl.uniform1f(gl.getUniformLocation(program, "u_b"), settings.b);
gl.uniform1f(gl.getUniformLocation(program, "u_c"), settings.c);
gl.uniform1f(gl.getUniformLocation(program, "u_d"), settings.d);
gl.useProgram(null);
return program;
}
Insert cell
timestepPosition = gl.getAttribLocation(timestepProgram, "a_position")
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more