Skip to content

Conversation

@davepagurek
Copy link
Contributor

@davepagurek davepagurek commented Oct 21, 2025

This refactors RendererGL into two classes, Renderer3D, and a subclass RendererGL. It also introduces a new RendererWebGPU that extends Renderer3D as well.

No WebGPU code is bound by default. Currently it can be tested just by importing its addon module and setting it up, e.g. this test sketch using textures and framebuffers:

WebGPU test sketch source code
import p5 from '../src/app.js';
import rendererWebGPU from '../src/webgpu/p5.RendererWebGPU.js';

p5.registerAddon(rendererWebGPU);

const sketch = function (p) {
  let fbo;
  let sh;
  let tex;

  p.setup = async function () {
    await p.createCanvas(400, 400, p.WEBGPU);
    fbo = p.createFramebuffer();

    tex = p.createImage(100, 100);
    tex.loadPixels();
    for (let x = 0; x < tex.width; x++) {
      for (let y = 0; y < tex.height; y++) {
        const off = (x + y * tex.width) * 4;
        tex.pixels[off] = p.round((x / tex.width) * 255);
        tex.pixels[off + 1] = p.round((y / tex.height) * 255);
        tex.pixels[off + 2] = 0;
        tex.pixels[off + 3] = 255;
      }
    }
    tex.updatePixels();
    fbo.draw(() => {
      p.imageMode(p.CENTER);
      p.image(tex, 0, 0, p.width, p.height);
    });

    sh = p.baseMaterialShader().modify({
      uniforms: {
        'f32 time': () => p.millis(),
      },
      'Vertex getWorldInputs': `(inputs: Vertex) {
        var result = inputs;
        result.position.y += 40.0 * sin(uniforms.time * 0.005);
        return result;
      }`,
    })
  };

  p.draw = function () {
    p.orbitControl();
    const t = p.millis() * 0.002;
    p.background(200);
    p.shader(sh);
    p.ambientLight(150);
    p.directionalLight(100, 100, 100, 0, 1, -1);
    p.pointLight(155, 155, 155, 0, -200, 500);
    p.specularMaterial(255);
    p.shininess(300);
    p.noStroke();
    for (const [i, c] of ['red', 'lime', 'blue'].entries()) {
      p.push();
      p.fill(c);
      p.translate(
        p.width/3 * p.sin(t + i * Math.E),
        0,
        p.width/3 * p.sin(t * 1.2 + i * Math.E + 0.3),
      )
      p.texture(fbo)
      p.sphere(30);
      p.pop();
    }
  };
};

new p5(sketch);

Notes

  • Tests do not currently run on CI, only locally! In a separate PR (Run WebGPU tests on self-hosted runner davepagurek/p5.js#2) I've separated out the tests that need a GPU to run and have them running on a self-hosted runner. That PR can also be adapted to run those tests on a runner on e.g. Azure if we need too. For now though, they only will be run manually on your own computer.
  • In WEBGPU mode, you need to await createCanvas(w, h, WEBGPU)
  • In WebGPU mode, you have to await loadPixels() and await get()
  • The WebGPU implementation is actually pretty usable but is not fully complete. Remaining features include:
    • imageLight()
    • filter shaders
    • font rendering
    • p5.strands (currently shader hooks work, but only written in WGSL, not in js)
    • clipping
  • The current goal is just feature parity. We will definitely want to then optimize performance more.

@davepagurek
Copy link
Contributor Author

Update: added a WGSL backend for p5.strands!

This silly little demo is running this shader:

baseMaterialShader().modify(() => {
  const time = uniformFloat(() => millis())
  p.getWorldInputs((inputs) => {
    inputs.position.y += 40 * sin(time * 0.005);
    return inputs;
  });
})
Screen.Recording.2025-11-22.at.7.29.16.PM.mov

davepagurek and others added 3 commits November 30, 2025 15:37
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@davepagurek
Copy link
Contributor Author

Update: filter shaders now work in WebGPU! also the base filter implementations are now in p5.strands so that we get both implementations "for free"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants