npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

wgpu-matrix

v2.8.0

Published

fast matrix math library for WebGPU

Downloads

2,348

Readme

wgpu-matrix

NPM Package

Fast 3d math library for webgpu

Why another 3d math library?

  • 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.
  • 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);

Usage

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.min.js';

// ... etc ...

or via npm

npm install --save wgpu-matrix

then using a build process

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

// ... etc ...

Example

Download

Notes

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

Important!

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.

Columns vs Rows

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 😌

Performance vs Convenience

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. 😉

Migration

1.x -> 2.x

  • 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.

Development

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.

License

MIT