Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement load/updatePixels() and get() for framebuffers #6109

Merged
merged 6 commits into from
May 3, 2023

Conversation

davepagurek
Copy link
Contributor

@davepagurek davepagurek commented Apr 19, 2023

Resolves #6082

This branches off of #5981 (since it also fixes WebGL pixels[] being inverted in the y axis), so we should review/merge that first.

Changes

  • Adds support for loadPixels/pixels/updatePixels/get for p5.Framebuffer
    • These do not need to flip the y axis, since we already flip framebuffer content using its camera
    • Like get() for p5.Graphics, the resulting p5.Image will always have a pixel density of 1 even if the source content has higher density
  • Adds support for updatePixels for WebGL main canvases or graphics
    • Each WebGL renderer has a framebuffer it uses and caches that it can update the pixels of and then draw to the canvas
    • Just using a p5.Texture would be a tad cheaper, so we could switch to that eventually if we want, but I suspect we'll want to use a framebuffer in the future for filter(). Happy to discuss though!

Screenshots of the change

Some example code drawing in 3D, updating pixels, then drawing some more: (Live version)

function setup() {
  createCanvas(400, 400, WEBGL);
  setAttributes({ antialias: true })
}

function draw() {
  background(0);
  noStroke();
  lights();
  sphere(100);
  loadPixels();
  for (let y = 200; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const idx = (y * width + x) * 4;
      pixels[idx] = (x / width) * 255;
      pixels[idx + 1] = (y / height) * 255;
      pixels[idx + 2] = 255;
      pixels[idx + 3] = 255;
    }
  }
  updatePixels();
  
  push();
  translate(100, 100);
  rotateX(0.5);
  rotateY(0.5);
  box();
  pop();
  noLoop();
}

image

Some similar code using a framebuffer (used as an example for the docs of framebuffer's updatePixels): (Live version)

let framebuffer;
function setup() {
  createCanvas(100, 100, WEBGL);
  framebuffer = createFramebuffer({ antialias: true });
}

function draw() {
  noStroke();
  lights();
  
  framebuffer.begin();
  background(0);
  sphere(25);
  framebuffer.end();
  framebuffer.loadPixels();
  for (let y = height/2; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const idx = (y * width + x) * 4;
      framebuffer.pixels[idx] = (x / width) * 255;
      framebuffer.pixels[idx + 1] = (y / height) * 255;
      framebuffer.pixels[idx + 2] = 255;
      framebuffer.pixels[idx + 3] = 255;
    }
  }
  framebuffer.updatePixels();
  
  framebuffer.begin();
  push();
  translate(20, 20);
  rotateX(0.5);
  rotateY(0.5);
  box(20);
  pop();
  framebuffer.end();
  
  image(framebuffer, -width/2, -height/2);
  noLoop();
}

image

PR Checklist

  • npm run lint passes
  • [Inline documentation] is included / updated
  • [Unit tests] are included / updated

Copy link
Contributor

@aferriss aferriss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome, thanks for putting this together @davepagurek . I left a couple notes on the PR.

One more thing that comes to mind is to check that if multiple fbo's are in the same sketch that calling loadPixels and updatePixels in arbitrary order still works as expected. For ex:

fbo1.loadPixels();
fbo2.loadPixels();
fbo2.updatePixels();
fbo1.updatePixels();

Another circumstance I wonder if we can catch is when someone tries to manipulate the pixel arrays or call updatePixels before loadPixels has been called. Perhaps a warning in those cases could help solve some programmer error.

src/webgl/p5.Framebuffer.js Outdated Show resolved Hide resolved
src/webgl/p5.Framebuffer.js Show resolved Hide resolved
src/webgl/p5.Framebuffer.js Show resolved Hide resolved
src/webgl/p5.Framebuffer.js Show resolved Hide resolved
src/webgl/p5.Framebuffer.js Outdated Show resolved Hide resolved
src/webgl/p5.Framebuffer.js Show resolved Hide resolved
src/webgl/p5.RendererGL.Retained.js Show resolved Hide resolved
src/webgl/p5.RendererGL.js Show resolved Hide resolved
src/webgl/p5.RendererGL.js Outdated Show resolved Hide resolved
src/webgl/shaders/line.vert Show resolved Hide resolved
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.

Add a way to read back pixels from p5.Framebuffer
2 participants