How to Build a GPU-Accelerated Image Filter with WebGL and JavaScript

WebGL is a JavaScript API that enables rendering high-performance 2D and 3D graphics directly in the browser using the GPU. In this article, we’ll walk through building an image filter (like grayscale or blur) using WebGL shaders and JavaScript. This a…


This content originally appeared on DEV Community and was authored by HexShift

WebGL is a JavaScript API that enables rendering high-performance 2D and 3D graphics directly in the browser using the GPU. In this article, we'll walk through building an image filter (like grayscale or blur) using WebGL shaders and JavaScript. This allows for real-time processing and smooth performance, even with large images.

1. Why Use WebGL for Image Filtering?

Traditional image manipulation using Canvas or JavaScript loops is CPU-bound and slow for high-res images. WebGL leverages GPU shaders to handle pixel-level transformations in parallel, delivering speed and responsiveness crucial for modern UI effects and photo editors.

2. Basic HTML Setup

Start with a simple page layout and an image to filter:

<canvas id="glcanvas" width="500" height="500"></canvas>
<img id="source" src="image.jpg" crossorigin="anonymous" style="display:none;" />

3. WebGL Shader Basics

You’ll need a vertex shader and a fragment shader. The vertex shader maps the image onto a rectangle, and the fragment shader processes each pixel.

const vertexShaderSource = `
attribute vec2 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;

void main() {
  gl_Position = vec4(a_position, 0, 1);
  v_texCoord = a_texCoord;
}`;
const fragmentShaderSource = `
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D u_image;

void main() {
  vec4 color = texture2D(u_image, v_texCoord);
  float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
  gl_FragColor = vec4(vec3(gray), 1.0);
}`;

4. Initializing WebGL Context

Set up the WebGL rendering context and compile shaders:

const canvas = document.getElementById('glcanvas');
const gl = canvas.getContext('webgl');

function createShader(gl, type, source) {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  return shader;
}

const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

5. Rendering the Image with Filter

Create and link the WebGL program, load the image texture, and draw the filtered output:

function createProgram(gl, vShader, fShader) {
  const program = gl.createProgram();
  gl.attachShader(program, vShader);
  gl.attachShader(program, fShader);
  gl.linkProgram(program);
  return program;
}

const program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);

const positionLocation = gl.getAttribLocation(program, "a_position");
const texCoordLocation = gl.getAttribLocation(program, "a_texCoord");

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -1, -1, 1, -1, -1, 1,
  -1, 1, 1, -1, 1, 1,
]), gl.STATIC_DRAW);

Then load the image and draw:

const image = document.getElementById('source');
image.onload = () => {
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,
                gl.UNSIGNED_BYTE, image);
  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);
  
  gl.viewport(0, 0, canvas.width, canvas.height);
  gl.drawArrays(gl.TRIANGLES, 0, 6);
};

6. Going Further

  • Add a UI to switch filters (blur, sepia, invert, etc.)
  • Support video textures for real-time webcam effects
  • Export the filtered image using canvas.toDataURL()

Conclusion

WebGL is a powerful tool for building high-performance, interactive visual effects in the browser. This simple grayscale filter can be extended into a full-featured image editor or dynamic UI component, all running smoothly thanks to GPU acceleration.

If this post helped you, consider supporting me here: buymeacoffee.com/hexshift


This content originally appeared on DEV Community and was authored by HexShift


Print Share Comment Cite Upload Translate Updates
APA

HexShift | Sciencx (2025-04-18T03:32:38+00:00) How to Build a GPU-Accelerated Image Filter with WebGL and JavaScript. Retrieved from https://www.scien.cx/2025/04/18/how-to-build-a-gpu-accelerated-image-filter-with-webgl-and-javascript/

MLA
" » How to Build a GPU-Accelerated Image Filter with WebGL and JavaScript." HexShift | Sciencx - Friday April 18, 2025, https://www.scien.cx/2025/04/18/how-to-build-a-gpu-accelerated-image-filter-with-webgl-and-javascript/
HARVARD
HexShift | Sciencx Friday April 18, 2025 » How to Build a GPU-Accelerated Image Filter with WebGL and JavaScript., viewed ,<https://www.scien.cx/2025/04/18/how-to-build-a-gpu-accelerated-image-filter-with-webgl-and-javascript/>
VANCOUVER
HexShift | Sciencx - » How to Build a GPU-Accelerated Image Filter with WebGL and JavaScript. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/04/18/how-to-build-a-gpu-accelerated-image-filter-with-webgl-and-javascript/
CHICAGO
" » How to Build a GPU-Accelerated Image Filter with WebGL and JavaScript." HexShift | Sciencx - Accessed . https://www.scien.cx/2025/04/18/how-to-build-a-gpu-accelerated-image-filter-with-webgl-and-javascript/
IEEE
" » How to Build a GPU-Accelerated Image Filter with WebGL and JavaScript." HexShift | Sciencx [Online]. Available: https://www.scien.cx/2025/04/18/how-to-build-a-gpu-accelerated-image-filter-with-webgl-and-javascript/. [Accessed: ]
rf:citation
» How to Build a GPU-Accelerated Image Filter with WebGL and JavaScript | HexShift | Sciencx | https://www.scien.cx/2025/04/18/how-to-build-a-gpu-accelerated-image-filter-with-webgl-and-javascript/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.