processing / p5.js

p5.js is a client-side JS platform that empowers artists, designers, students, and anyone to learn to code and express themselves creatively on the web. It is based on the core principles of Processing. http://twitter.com/p5xjs —
http://p5js.org/
GNU Lesser General Public License v2.1
21.2k stars 3.23k forks source link

Graphics object used as mask results in image that is half the size of the original graphics object #6793

Closed taliacotton closed 2 months ago

taliacotton commented 5 months ago

Most appropriate sub-area of p5.js?

p5.js version

1.9.0

Web browser and version

Chrome 121.0.6167.139

Operating system

MacOSX

Steps to reproduce this

Steps:

  1. Create a p5.Graphics object the same size as canvas—I've called mine "maskGraphics"
  2. Draw something to the main canvas—in my case it's an image
  3. Use get() to save a the canvas as an image, then clear the canvas.
  4. Draw something to the new Graphics object that will be the mask—in my case it's an ellipse
  5. Use mask() to mask the main image using the newly drawn mask to the mask graphics object.
  6. When you draw both the display image and the mask graphics image, the masked image is half the size as the mask graphics object when they're both drawn at the same size. Screenshot 2024-02-04 at 2 07 13 PM

My gut is that it might have something to do with the device pixel ratio or the pixel density, but I have no reason to believe that and haven't been able to prove that.

Snippet:


let sketch = function(p) {
  let img, maskGraphics, cnv;

  p.preload = function() {
     img = p.loadImage("https://hips.hearstapps.com/hmg-prod/images/dog-puppy-on-garden-royalty-free-image-1586966191.jpg?crop=1xw:0.74975xh;center,top&resize=1200:*");
  };

  p.setup = () => {
      cnv = p.createCanvas(p.windowWidth, p.windowHeight);
      maskGraphics = p.createGraphics(p.windowWidth, p.windowHeight);
  }

  p.draw = () => {

        // draw an image to the main canvas
        p.image(img, 0,0,p.width, p.height);

        // save the canvas as an image, then clear the canvas
        let displayImage = p.get();
        p.clear();

        maskGraphics.clear();
        maskGraphics.fill(0);
        // Draw an ellipse to the mask graphics element in the center of the canvas
        maskGraphics.ellipse(p.width/2,p.height/2,300,300)

        // Apply the mask to displayImage
        // Without this, the image will be full size without the circle mask
        displayImage.mask(maskGraphics);

        // Draw the masked image
        // Without this, there will not be the masked image 
        p.image(displayImage, 0, 0, p.width, p.height);

        // Draw the mask circle  as an image to the main cnv to test its position on the canvas
        p.image(maskGraphics, 0, 0, p.width, p.height);
  };
}

new p5(sketch, 'container');
davepagurek commented 5 months ago

Thanks for filing this issue! I think this bug may be the same as https://github.com/processing/p5.js/issues/6770 -- @Papershine, maybe you can test this example on your PR to see if it fixes it too?

taliacotton commented 5 months ago

Thank you! Yes, I had actually tested adding pixelDensity(1) prior to contributing the issue, but then the quality of the sketch goes down significantly. If I add pixelDensity(2) it also fixes the issue, but on devices where the device pixel ratio is something else the sketch lags significantly because it's drawing at 2x the size. I tried pixelDensity(window.devicePixelRatio) but that didn't fix the issue.

Is there a solution that solves the misalignment without losing the quality of the sketch?

taliacotton commented 5 months ago

If it helps to debug, I just switched to version 1.4.1 per #6770, and that worked. However, not ideal for a long-term solution since I'd like to use the most recent version. Let's see if @Papershine's pull request solves it?

Papershine commented 5 months ago

Yep I've tried it with the code in the PR and this is how it looks - this should be what it looks like right?

Screenshot 2024-02-04 at 6 55 38 PM
taliacotton commented 5 months ago

whee yes! <3

taliacotton commented 5 months ago

Hey awesome P5 team, do you have any tips for what I should do in the meantime regarding this bug while the pull request is being approved? Clients eager to see things right.

aferriss commented 5 months ago

Hi! One option to use a shader to do the masking. Not sure if you can use webGL or not, but if you can it's a pretty short shader. Here's a quick example: https://editor.p5js.org/aferriss/sketches/qYWb4P49d

davepagurek commented 5 months ago

Another option, if your mask is shapes that you draw, is to use beginClip/endClip: https://p5js.org/reference/#/p5/beginClip

taliacotton commented 5 months ago

Awesome, thanks so much Dave. Will look into both of these.