P5.js: Request for clip() and noClip() in p5.js

Created on 10 Sep 2019  路  8Comments  路  Source: processing/p5.js

Hi team,

I recently found a situation where I really could have used clip() and noClip() from Java Processing. FYI, these calls provide clipping to within a rectangular area.

https://processing.org/reference/clip_.html

Just for context, the scenario was rendering a distorted grid pattern of quad()s and triangle()s, which had been stretched away from their original rectangular "frame". Like stretching a rubber chess board if you like, and rendering it within it's original size. It's a classic case where you need clipping, or the stencil buffer, to avoid a lot of work clipping individual polygons.

I don't see much discussion of clip() here, except an HTML issue here:

https://github.com/processing/p5.js/issues/2003

So, I'd be interested to hear comments on adding clip() and noClip(). Has anyone else felt they needed it but didn't raise an RFE ? etc etc.

Thanks, GE.

core feature request

Most helpful comment

Update:

A couple days later, I've got a small example working:
https://editor.p5js.org/Jh97uk/sketches/r2fiAiSlb

draw(){
  drawingContext.save(); // Save before clipping mask so you can undo it later on. ALWAYS DO THIS BEFORE TRANSLATIONS.
  fill(color('rgb(255, 0, 0)'));
  rect(10, 10, 50, 50)
  drawingContext.clip();
  fill(25);
  rect(20, 20, 100, 100)
  drawingContext.restore(); // Remove the clippping mask and go back to normal.
}

So basically what's happening here is that, we use Canvas's inbuilt clipping function on top of p5JS.

First we save the canvas before we clip, becasue we need to restore it to its previous state after we're done clipping so that we can draw other stuff.

Then, we draw our parent shape, and then call the clip function to limit the rendering of any shapes inside that shape. We then draw our shape we want contained, and restore the canvas afterwards in order to get rid of the clipping. Perfect! I don't know how this works exactly or how it might have adverse effects, but it looks great for now.

One thing worthy of note is that you should always save the canvas before translations, if you don't then you will end up being stuck with the translation you made before saving the canvas.

This works perfectly for what I wanted it for. Hopefully this helps someone!

All 8 comments

Hi @grege2 thanks for the suggestion!

Just to get a sense of how hard it would be to do this in p5 as-is, I recreated that Processing example. As you can see, it is really only a few additional lines of code. Since it is possible to accomplish something similar, recreating Processing's version of clip doesn't feel like a priority.

That said, I looked around briefly and realized that the Canvas API's clip() does offer a bunch of neat opportunities for controlled, custom masking that p5 could expose through something like 'clip'/'noClip'. If more features are to be considered, then I think a good argument could be made for this one, the pipeline for making an asset to use with mask() can be arduous for some.

I think this is ok to implement according to the native canvas's clip() as the Processing one is only limited to rectangles while the native one provides much more possibilities.

Hi @stalgiag et al, thanks for the comments. Yes, I could clip my gfx by rendering it in another buffer/canvas, and copying back a rectangular area to my main canvas. At present, there's a fair bit of gfx (a mesh of guidelines and markers - the chessboard is not always completely rendered) rendered "underneath" the chess board thingy, so I think I would have to first copy all that to the auxiliary canvas, render on top of that, and copy it back. Not so bad. Or I could get fancy with alpha and blend the new gfx back into the main canvas. It could all work fine, but clip() and noClip() would be so easy.

Re the native canvas clip), would that interact properly with p5.js rendering ? I'm familiar with OpenGL clip planes (3D) and stencil planes (screen-space 2D), but not HTML clip.

Best, GE.

Hi all, I will try to retro-fit the "off screen" canvas method and report back. It may be bit harder to retro-fit into my already tangled mess of code, than plan it this way in the first place, but should be ok. If you could keep this issue open for at least say a couple of weeks that would keep things unpressured, grazie. A presto.

@grege2 I think there is some interest in making a more robust 'clip state' feature. This could theoretically allow any shapes drawn between clip and noClip to mask the drawing underneath.

Not sure if it will actually happen, but just wanted to state that this has some degree of interest, so the issue can stay open to allow discussion.

Hi all, just thought I should freshen this issue, to say clip() and noClip() would still be very useful for me. I've been working on the code I mentioned above (stretched chessboard thing - there's a lot more to it than that, but that's a simple analogy) and I'm at the point where I'm reworking a bunch of code and again I could really use clip(). But I have a plan to try rendering off-screen and pulling back just the rectangular area I need, I will report how it goes. @stalgiag Thanks for keeping this open.

Hi. I'm looking for something similar to you @grege2 ... Did you come up with any solutions at all? I really need clipping for individual shapes within p5JS... I need to be able to draw text within a rect that doesnt exceed its bounds.

Thanks!

Update:

A couple days later, I've got a small example working:
https://editor.p5js.org/Jh97uk/sketches/r2fiAiSlb

draw(){
  drawingContext.save(); // Save before clipping mask so you can undo it later on. ALWAYS DO THIS BEFORE TRANSLATIONS.
  fill(color('rgb(255, 0, 0)'));
  rect(10, 10, 50, 50)
  drawingContext.clip();
  fill(25);
  rect(20, 20, 100, 100)
  drawingContext.restore(); // Remove the clippping mask and go back to normal.
}

So basically what's happening here is that, we use Canvas's inbuilt clipping function on top of p5JS.

First we save the canvas before we clip, becasue we need to restore it to its previous state after we're done clipping so that we can draw other stuff.

Then, we draw our parent shape, and then call the clip function to limit the rendering of any shapes inside that shape. We then draw our shape we want contained, and restore the canvas afterwards in order to get rid of the clipping. Perfect! I don't know how this works exactly or how it might have adverse effects, but it looks great for now.

One thing worthy of note is that you should always save the canvas before translations, if you don't then you will end up being stuck with the translation you made before saving the canvas.

This works perfectly for what I wanted it for. Hopefully this helps someone!

Was this page helpful?
0 / 5 - 0 ratings