Fast 3d math library for webgpu

- Most other 3D math libraries are designed for WebGL, not WebGPU
- WebGPU uses clip space Z 0 to 1, vs WebGL -1 to 1. So
`ortho`

,`perspective`

,`frustum`

are different - WebGPU mat3s are 12 floats (padded), WebGL they're 9.

- WebGPU uses clip space Z 0 to 1, vs WebGL -1 to 1. So
- Many other 3D math libraries are overly verbose
compare

`// wgpu-matrix`

const t = mat4.translation([x, y, z]);

const p = mat4.perspective(fov, aspect, near, far);

const r = mat4.rotationX(rad);`// gl-matrix`

const t = mat4.create();

mat4.fromTranslation(t, [x, y, z]);

const p = mat4.create();

mat4.perspective(p, fov, aspect, near, far);

const r = mat4.create();

mat4.fromXRotation(r, rad);note that if you want to pre-create matrices you can still do this in wgpu-matrix

`const t = mat4.create();`

mat4.translation([x, y, z], t);

const p = mat4.create();

mat4.perspective(fov, aspect, near, far, p);

const r = mat4.create();

mat4.rotationX(rad, r);

`import {`

vec3,

mat4,

} from 'https://wgpu-matrix.org/dist/2.x/wgpu-matrix.module.js';

const fov = 60 * Math.PI / 180

const aspect = width / height;

const near = 0.1;

const far = 1000;

const perspective = mat4.perspective(fov, aspect, near, far);

const eye = [3, 5, 10];

const target = [0, 4, 0];

const up = [0, 1, 0];

const view = mat4.lookAt(eye, target, up);

Note: for translation, rotation, and scaling there are 2 versions of each function. One generates a translation, rotation, or scaling matrix. The other translates, rotates, or scales a matrix.

`const t = mat4.translation([1, 2, 3]); // a translation matrix`

const r = mat4.rotationX(Math.PI * 0.5); // a rotation matrix

const s = mat4.scaling([1, 2, 3]); // a scaling matrix

`const m = mat4.identity();`

const t = mat4.translate(m, [1, 2, 3]); // m * translation([1, 2, 3])

const r = mat4.rotateX(m, Math.PI * 0.5); // m * rotationX(Math.PI * 0.5)

const s = mat4.scale(m, [1, 2, 3]); // m * scaling([1, 2, 3])

Functions take an optional destination to hold the result.

`const m = mat4.create(); // m = new mat4`

mat4.identity(m); // m = identity

mat4.translate(m, [1, 2, 3], m); // m *= translation([1, 2, 3])

mat4.rotateX(m, Math.PI * 0.5, m); // m *= rotationX(Math.PI * 0.5)

mat4.scale(m, [1, 2, 3], m); // m *= scaling([1, 2, 3])

There is also the minified version

`import {`

vec3,

mat4,

} from 'https://wgpu-matrix.org/dist/2.x/wgpu-matrix.module.js';

// ... etc ...

or via npm

```
npm install --save wgpu-matrix
```

then using a build process

`import {vec3, mat3} from 'wgpu-matrix';`

// ... etc ...

`mat4.perspective`

,
`mat4.ortho`

, and
`mat4.frustum`

all return matrices with Z clip space from 0 to 1 (unlike most WebGL matrix libraries which return -1 to 1)

`mat4.create`

makes an all zero matrix if passed no parameters.
If you want an identity matrix call `mat4.identity`

`mat3`

uses the space of 12 elements

`// a mat3`

[

xx, xy, xz, ?

yx, yy, yz, ?

zx, zy, zz, ?

]

This is because WebGPU requires mat3s to be in this format and since this library is for WebGPU it makes sense to match so you can manipulate mat3s in TypeArrays directly.

`vec3`

in this library uses 3 floats per but be aware that an array of
`vec3`

in a Uniform Block or other structure in WGSL, each vec3 is
padded to 4 floats! In other words, if you declare

`struct Foo {`

bar: vec3<f32>[3];

};

then bar[0] is at byte offset 0, bar[1] at byte offset 16, bar[2] at byte offset 32.

See the WGSL spec on alignment and size.

WebGPU follows the same conventions as OpenGL, Vulkan, Metal for matrices. Some people call this "column major". The issue is the columns of a traditional "math" matrix are stored as rows when declaring a matrix in code.

`[`

x1, x2, x3, x4, // <- column 0

y1, y2, y3, y4, // <- column 1

z1, z2, z3, z4, // <- column 2

w1, w2, w3, w4, // <- column 3

]

To put it another way, the translation vector is in elements 12, 13, 14

`[`

xx, xy, xz, 0, // <- x-axis

yx, yy, yz, 0, // <- y-axis

zx, zy, zz, 0, // <- z-axis

tx, ty, tz, 1, // <- translation

]

This issue has confused programmers since at least the early 90s ðŸ˜Œ

Most functions take an optional destination as the last argument. If you don't supply it, a new one (vector, matrix) will be created for you.

`// convenient usage`

const persp = mat4.perspective(fov, aspect, near, far);

const camera = mat4.lookAt(eye, target, up);

const view = mat4.inverse(camera);

`// performant usage`

// at init time

const persp = mat4.create();

const camera = mat4.create();

const view = mat4.create();

// at usage time

mat4.perspective(fov, aspect, near, far, persp);

mat4.lookAt(eye, target, up, camera);

mat4.inverse(camera, view);

For me, most of the stuff I do in WebGPU, the supposed performance I might lose from using the convenient style is so small as to be unmeasurable. I'd prefer to stay convenient and then, if and only if I find a performance issue, then I might bother to switch to the performant style.

As the saying goes *premature optimization is the root of all evil.* ðŸ˜‰

`mat4.lookAt`

changed from a "camera matrix" to a "view matrix" (same as gluLookAt). If you want a matrix that orients an something in world space see`mat4.aim`

. Sorry about this change but people are used to lookAt making a a view matrix and it seemed prudent to make this change now and save more people from frustration going forward.

`git clone https://github.com/greggman/wgpu-matrix.git`

cd wgpu-matrix

npm i

npm run build

npm test

You can run tests in the browser by starting a local server

```
npx servez
```

Now go to wherever your server serves pages. In the case of `servez`

that's
probably http://localhost:8080/test/.

By default the tests test the minified version. To test the source use `src=true`

as in http://localhost:8080/test/?src=true.

To limit which tests are run use `grep=<regex>`

. For example
http://localhost:8080/test/?src=true&grep=mat3.*?translate
runs only tests with `mat3`

followed by `translate`

in the name of test.