Masking a createGraphics object generates lag

So I’m creating this animated character who needs to have their pupils stay inside the whites of their eyes. Since you can’t use mask() on a graphics object, I have to convert the pupils to an image using createImage and copy(), and then apply the mask() function. My code was running buttery smooth with pretty much no lag, but the moment I added this tiny bit of masking code, the framerate started stuttering. Now, I’ve optimized this as much as I can, the only time I’m masking the eyes are when the eyes are actually moving and need to be redrawn, but this still creates a noticeable slowdown and jittery movements that were not present before. There has got to be a better solution to this.

This is the code that is causing the slowdown and it is run every frame while the pupils are moving.

let pupils = gc.pupils.cnv; // the createGraphics object for the pupils
let whites = gc.eyes.cnv; // the createGraphics object for the whites
let pupilsImg = createImage(pupils.width, pupils.height);
pupilsImg.copy(pupils, 0, 0, pupils.width, pupils.height, 0, 0, pupils.width, pupils.height);
image(whites, 0, 0);
image(pupilsImg, 0, 0);

If there is not another way to create like a clipping mask in p5js for graphics, im going to pull my hair out lol. Maybe is there some sort of hacky html canvas thing i can try?

1 Like

try using thread() function. It runs a function and continues the code without worrying about the time the function in thread takes to run.

Edit: its for processing not p5. Try finding something similar

setTimeout() seems to create a seperate thread. I’ll try setTimeout() and come back with the results. My only concern is that the eyes are drawn to the screen on the very next line after the image is masked, so the eyes will always be one frame behind. The issue I’m seeing with this is that once an animation completes, the code that updates the graphics buffer stops running to save time, so if the animation stops before the eyes get there, they’re gonna be stuck at like the second-to-last frame of animation at least. I’ll see what happens.

Edit: I could solve that last issue I mentioned by putting the function that draws the eyes to the screen in that separate thread, but then that would defeat the whole purpose because then it’s still only drawing the eyes once the image mask function completes. Also I’m noticing that sometimes it doesn’t even lag! It’s only sometimes. I set a function to draw the deltaTime to the screen and it seems like there are these random lag spikes that are causing the issue. And these lag spikes seem to be mostly concentrated at the start of the program and become more sparse as the program runs for longer.

OKAY so I think i figured it out. I don’t know why I didn’t notice this earlier, but I was running createImage() every frame that the eyes are moving, so it’s creating a new p5.image object every frame. I moved the createImage() part out of the loop and just put it in the constructor for my character object so it only gets called once with setup() and now the lag is virtually gone. There’s still like lag spikes at the start of the program that sorta get more sparse as the program continues running but they are way less intense.

One thing I will add tho is that when I’m not creating a new image every frame and im just running copy() on the same image over and over, it’s not clearing the contents of the image every frame so it kinda smears and leaves a trail. Normally I’d just use background() to fix this but if I put a 100% transparent color in for background() it wouldn’t do anything, so I had to make another image in the constructor called transparent, and I use that to mask() the image every frame so we don’t get that smear.

1 Like