Mapping this.thread.x and this.thread.y in gpu.js

In gpu.js, 2D kernels execute concurrently across a grid of parallel threads where this.thread.x and this.thread.y serve as the unique spatial indices for each thread. When defining a 2D output dimensions array, gpu.js utilizes a standard Cartesian coordinate system where (0, 0) begins at the bottom-left corner rather than the top-left corner commonly used in standard web canvas and DOM operations. Understanding how these thread indices correspond to matrix dimensions, rows, and columns is critical for accurate data transformation, image processing, and mathematical computations.

The Dimension Grid

When creating a 2D kernel in gpu.js, you define the output dimensions via an array passed to setOutput([width, height]).

Inside the kernel function, gpu.js maps threads across this 2D plane:

Cartesian Orientation (Bottom-Left Origin)

Because gpu.js runs on top of WebGL, it inherently follows the OpenGL texture coordinate convention. The origin (0, 0) is located at the bottom-left of the output array:

Mapping to 2D Arrays and Matrices

In standard JavaScript, 2D arrays are commonly indexed as array[row][column], which conceptually treats (0, 0) as the top-left element. When reading from or writing to a traditional 2D array or matrix inside a gpu.js kernel:

To access an element matching Cartesian coordinates:

const value = inputMatrix[this.thread.y][this.thread.x];

If your input data assumes the top-left corner is (0, 0) (such as standard image pixel data or typical nested arrays) and you want to maintain that orientation in the output, invert the Y-axis coordinate:

const invertedY = (height - 1) - this.thread.y;
const value = inputMatrix[invertedY][this.thread.x];

Flattening to 1D Buffer Indices

When working with flattened 1D arrays (such as an ImageData buffer or a flattened matrix of size width * height), convert the 2D thread coordinates into a single linear index using the following formula:

const index = (this.thread.y * width) + this.thread.x;

For RGBA image buffers containing four values per pixel:

const pixelIndex = ((this.thread.y * width) + this.thread.x) * 4;
const red   = imageBuffer[pixelIndex];
const green = imageBuffer[pixelIndex + 1];
const blue  = imageBuffer[pixelIndex + 2];
const alpha = imageBuffer[pixelIndex + 3];