Public
Edited
Jan 8, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof gl = {
const canvas = DOM.canvas(width, height);
canvas.value = canvas.getContext("webgl");
return canvas;
}
Insert cell
height = ~~(width * 9) / 16
Insert cell
program = {
const program = gl.createProgram();

var shader;
if (selectFilter === "SNN") shader = fragmentShaderSNN;
if (selectFilter === "Outline") shader = fragmentShaderOutline;

gl.attachShader(program, vertexShader);
gl.attachShader(program, shader);
gl.linkProgram(program);

if (gl.getProgramParameter(program, gl.LINK_STATUS)) return program;
throw new Error(gl.getProgramInfoLog(program));
}
Insert cell
draw = {
const u_size = gl.getUniformLocation(program, "u_size");
const a_vertex = gl.getAttribLocation(program, "a_vertex");

gl.useProgram(program);

gl.enableVertexAttribArray(a_vertex);
gl.vertexAttribPointer(a_vertex, 2, gl.FLOAT, false, 0, 0);

gl.uniform1f(u_size, Math.max(viewof gl.width, viewof gl.height));

while (true) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
yield;
}
}
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)) return shader;
throw new Error(gl.getShaderInfoLog(shader));
}
Insert cell
fragmentShaderSNN = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(
shader,
`
precision mediump float;

// our texture
uniform sampler2D u_image;
uniform float u_size;
#define KERNEL_SIZE ${KERNEL_SIZE}
#define HALF_SIZE (KERNEL_SIZE / 2)

void main() {
float u_pixelsCountRev = 1.0 / float(KERNEL_SIZE * KERNEL_SIZE) * 4.0;
vec2 textCoord = vec2(gl_FragCoord.x / u_size, 1.0 - gl_FragCoord.y / u_size);
vec2 onePixel = vec2(1.0, 1.0) / u_size;
vec4 meanColor = vec4(0);
vec4 v = texture2D(u_image, textCoord);
int count = 0;
for (int y = 0; y <= HALF_SIZE; y+=2){
for (int x = -HALF_SIZE; x <= HALF_SIZE; x+=2){
vec4 v1 = texture2D(u_image, textCoord + vec2(x, y) * onePixel);
vec4 v2 = texture2D(u_image, textCoord + vec2(-x, -y) * onePixel);
vec4 d1 = abs(v - v1);
vec4 d2 = abs(v - v2);
vec4 rv = vec4(((d1[0] < d2[0]) ? v1[0] : v2[0]),
((d1[1] < d2[1]) ? v1[1] : v2[1]),
((d1[2] < d2[2]) ? v1[2] : v2[2]),1);
meanColor += rv;
}
}
gl_FragColor = meanColor * u_pixelsCountRev;
}
`
);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
throw new Error(gl.getShaderInfoLog(shader));
}
Insert cell
fragmentShaderOutline = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(
shader,
`
precision highp float;

uniform sampler2D u_image;
uniform float u_size;

void main() {
float x = gl_FragCoord.x / u_size;
float y = 1.0 - gl_FragCoord.y / u_size;
float px = 1.0 / u_size;
vec3 a0 = texture2D(u_image, vec2(x - px, y + px)).xyz;
vec3 a1 = texture2D(u_image, vec2(x, y + px)).xyz;
vec3 a2 = texture2D(u_image, vec2(x + px, y + px)).xyz;
vec3 a3 = texture2D(u_image, vec2(x - px, y)).xyz;
vec3 a5 = texture2D(u_image, vec2(x + px, y)).xyz;
vec3 a6 = texture2D(u_image, vec2(x - px, y - px)).xyz;
vec3 a7 = texture2D(u_image, vec2(x, y - px)).xyz;
vec3 a8 = texture2D(u_image, vec2(x + px, y - px)).xyz;
vec3 gx = -a0 + a2 - 2.0 * a3 + 2.0 * a5 - a6 + a8;
vec3 gy = -a0 - 2.0 * a1 - a2 + a6 + 2.0 * a7 + a8;
gl_FragColor = vec4(sqrt(gx * gx + gy * gy), 1.0);
}
`
);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
throw new Error(gl.getShaderInfoLog(shader));
}
Insert cell
{
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
return texture;
}
Insert cell
{
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
video = {
const video = document
.createElement("div")
.appendChild(html`<video autoplay playsinline>`);

const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: { ideal: width },
height: { ideal: height },
frame: { ideal: 5 }
},
audio: false
});
yield video;

video.srcObject = stream;
video.play();
invalidation.then(() => stream.getTracks().forEach((t) => t.stop()));
}
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