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

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