Published
Edited
Apr 24, 2020
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function createAndSetupTexture(gl) {
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// Set up texture so we can render any size image and work with pixels
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.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
return texture;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const canvas = html`<canvas width=600 height=500></canvas>`;
yield canvas;
const gl = canvas.getContext('webgl2');

const vertexShader = createShader(gl,gl.VERTEX_SHADER,vertexShaderCode.value)
const fragmentShader = createShader(gl,gl.FRAGMENT_SHADER,fragmentShaderCode.value)
const program = createProgram(gl,vertexShader, fragmentShader);
// Tell it to use our program (pair of shaders)
gl.useProgram(program);
// look up where vertex data needs to go
var positionAttrLocation = gl.getAttribLocation(program,'a_position');
var texCoordAttribLocation = gl.getAttribLocation(program,'a_texCoord');
// lookup uniforms
var resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
var imageLocation = gl.getUniformLocation(program, 'u_image');
// Create a vertexs array object
var vao = gl.createVertexArray();
// make it the one we're currently working with
gl.bindVertexArray(vao);
// create buffer and put one pixel space rect in it (2 triangles)
const positionBuffer = gl.createBuffer();
//Turn on the attribute
gl.enableVertexAttribArray(positionAttrLocation);
// Bind it to ARRAY_BUFFEE (Array_Buffer = positionBuffer
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell attribute how to get data out of posBuffer
var size = 2;
var type = gl.FLOAT;
var norm = false;
var stride = 0;
var offset = 0;
gl.vertexAttribPointer(positionAttrLocation, size, type, norm, stride, offset)
// provide texture coordinates for the rectangle
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0,
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordAttribLocation);
var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var norm = false; // don't normalize the data
var stride = 0;
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(texCoordAttribLocation,size,type,norm,stride,offset)
// Create texture and put the image in it
var originalImageTexture = createAndSetupTexture(gl);
// Upload image into texture
var mipLevel = 0; // the largest mip
var internalFormat = gl.RGBA // format we want in the texture
var srcFormat = gl.RGBA // format of the data
var srcType = gl.UNSIGNED_BYTE // type of supplied data
gl.texImage2D(gl.TEXTURE_2D,
mipLevel,
internalFormat,
srcFormat,
srcType,
image
);
// create 2 textures and attach them to framebuffers
var textures = [];
var framebuffers = [];
for(var ii=0; ii<2; ii++){
var texture = createAndSetupTexture(gl);
textures.push(texture);
// make the texture the same size as the image
var mipLevel = 0; // Largest mil
var internalFormat = gl.RGBA;
var border = 0;
var srcFormat = gl.RGBA;
var srcype = gl.UNSIGNED_BYTEl
var data = null;
gl.texImage2D(gl.TEXTURE_2D, mipLevel, internalFormat, image.width,
image.height, border, srcFormat, srcType, data
);
// Create framebuffer
var fbo = gl.createFramebuffer();
framebuffers.push(fbo);
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
// Attach a texture to it
var attachmentPoint = gl.COLOR_ATTACHMENT0;
gl.framebufferTexture2D(gl.FRAMEBUFFER,attachmentPoint, gl.TEXTURE_2D, texture, mipLevel);
}

var kernelLocation = gl.getUniformLocation(program, "u_kernel[0]");
var kernelWeightLocation = gl.getUniformLocation(program, "u_kernelWeight");
var flipYLocation = gl.getUniformLocation(program,'u_flipY');
/*
var edgeDetectKernel = kernelValue;
// set the kernel and it's weight
gl.uniform1fv(kernelLocation, edgeDetectKernel);
gl.uniform1f(kernelWeightLocation, computeKernelWeight(edgeDetectKernel));
*/
webglUtils.resizeCanvasToDisplaySize(gl.canvas)
// Tell webgl how to convert from clip space to pixels
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// bind attributes and buffers
gl.bindVertexArray(vao);
// Start with the original image on unit 0
gl.activeTexture(gl.TEXTURE0 + 0)
gl.bindTexture(gl.TEXTURE_2D, originalImageTexture);
// Pass in the canvas resolution so we can convert from
// pixels top clip space in shader
gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height);
// Tell the shader to get the texture from texture unit
gl.uniform1i(imageLocation, 0);
// don't y flip images while drawing to the textures
gl.uniform1f(flipYLocation, 1);
// Bind position buffer
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Set rect same size as image
setRectangle(gl, 0, 0, image.width, image.height);
kernelValues.forEach((name,i)=>{
setFramebuffer(framebuffers[i%2], image.width, image.height,gl, resolutionLocation);
drawWithKernel(gl,kernelLocation, kernelWeightLocation, name);
gl.bindTexture(gl.TEXTURE_2D, textures[i % 2])
})
gl.uniform1f(flipYLocation, -1);
setFramebuffer(null, gl.canvas.width, gl.canvas.height,gl, resolutionLocation);
drawWithKernel(gl,kernelLocation,kernelWeightLocation,'normal');
invalidation.then(d=>{
gl.deleteProgram(program);
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
})
}
Insert cell
function drawWithKernel(gl,kernelLocation,kernelWeightLocation,name){
const kernelValue = kernels[name];
gl.uniform1fv(kernelLocation, kernelValue);
gl.uniform1f(kernelWeightLocation,computeKernelWeightLocation(kernelValue));
// Draw the rectangle
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 6;
gl.drawArrays(primitiveType, offset, count);
}
Insert cell
function setFramebuffer(fbo, width, height,gl, resolutionLocation){
// make this the framebuffer we are rendering to
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.uniform2f(resolutionLocation, width, height);
gl.viewport(0, 0, width, height);
}
Insert cell
function computeKernelWeightLocation(kernel){
var weight = kernel.reduce((a,b)=>a+b);
return weight <= 0 ? 1:weight;
}
Insert cell
Insert cell
import {select} from "@jashkenas/inputs"
Insert cell
import {requireScript} from "@bumbeishvili/fetcher"
Insert cell
import {image,glsl} from "@bumbeishvili/webgl-fundamentals-image-processing"
Insert cell
webglUtils = requireScript('https://webglfundamentals.org/webgl/resources/webgl-utils.js')
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