Dynamic mask with blur from vector object. Alternatives.

Hi everyone. I’m glad to join Corona SDK community.
I’m just beginning to research framework capabilities so don’t laugh if my question is stupid or trivial.
Here is the task.
I’m trying to create something like a mask for the whole scene. The situation is pretty much the same as a Flashlight sample project but with some differences.
The most important difference is that I can’t use ready-to-use mask image, i.e. mask mus be dynamic.
Obviously the easiest way to create some shape is to use vector elements. In my case RoundedRect is almost exactly what I want. The main problem with vector objects is that I couldn’t find a way to blur the edges properly. Of course I can use filter.blurGaussian effect but it is heavy operation and I need to apply this in each frame which causes very poor performance when many (up to about 30-50) objects are used to create a compound “mask”.

I already tried several approaches and my last attempt was with snapshot. In fact I was able to get the result I want but I’m sure that the approach I’m using is not the most efficient.
​Could you please suggest what else I can do to achieve the same result as on the screenshot?

Maybe some trick with real mask? I tried that but I’m stuck at the moment when I need to change the dimentions of the mask (length or width in this particular case) w/o deforming it.

Again, this is almost the same as Flashlight from the samples but mask must by dynamic so I can’t use “blurry rounded rectangle” image because the width of the rectangle could be different in each frame.
Please check the code to see what I mean. This is full listing of the main.lua file

local centerX = display.contentCenterX local centerY = display.contentCenterY local w = display.actualContentWidth local h = display.actualContentHeight local image = display.newImageRect( "image.png", 768, 1024 ) image:translate( centerX, centerY ) -- snapshot local snapshot = display.newSnapshot(w, h) snapshot:translate(centerX, centerY) local background = display.newRect( 0, 0, w, h) background:setFillColor(0, 0, 0, 0.9) snapshot.canvas:insert(background) -- mask coord local maskX1, maskY1 = 50, 50 local maskX2, maskY2 = 500, 1000 local function refreshMask(maskX, maskY, destX, destY) -- add transparent mask local length = math.sqrt( (destX - maskX) ^ 2 + (destY - maskY) ^ 2) local deltaAngle = 360 - math.deg(math.atan2(destX - maskX, destY - maskY)) local mask = display.newRoundedRect(0, 0, 200, length, 100) mask.anchorX = 0.5 mask.anchorY = 0 mask.x = maskX - snapshot.x mask.y = maskY - snapshot.y mask.rotation = deltaAngle mask.fill.blendMode = { srcColor = "zero", dstColor="oneMinusSrcAlpha" } snapshot.canvas:insert(mask) -- blur masked image snapshot.fill.effect = "filter.blurGaussian" snapshot.fill.effect.horizontal.blurSize = 200 snapshot.fill.effect.vertical.blurSize = 200 -- refresh snapshot snapshot:invalidate("canvas") end local function screenTouch ( event ) if (event.phase == "moved") then -- clear snapshot because mask could be changed in each frame snapshot:invalidate() -- renew background snapshot.canvas:insert(background) -- draw compound mask refreshMask(maskX1, maskY1, event.x, event.y) refreshMask(maskX2, maskY2, event.x, event.y) end end local stage = display.getCurrentStage() stage:addEventListener("touch", screenTouch)

Hi @tananovsi,

Welcome to Corona! This is not a “trivial” question at all… it’s quite advanced actually. One idea you might not have considered is to compose the dynamic mask using the “9-slice” approach. Meaning, you’d have images for all 4 corners, and 4 more images to compose the sides of the mask. Depending on the width/height of the mask, you would assemble the corners, then scale (stretch) the sides to match up between them on all 4 sides. With this setup in place, you could take a snapshot of all that, and apply it using your positioning/rotation operations. In this way, you’d have a mask this is adjustable in both width and height, but it doesn’t warp or stretch or scale oddly (of course, there would need to be some minimum size enforced, so the corner pieces wouldn’t overlap each other).

Perhaps this approach will work for you.

Brent

Hi @tananovsi,

Welcome to Corona! This is not a “trivial” question at all… it’s quite advanced actually. One idea you might not have considered is to compose the dynamic mask using the “9-slice” approach. Meaning, you’d have images for all 4 corners, and 4 more images to compose the sides of the mask. Depending on the width/height of the mask, you would assemble the corners, then scale (stretch) the sides to match up between them on all 4 sides. With this setup in place, you could take a snapshot of all that, and apply it using your positioning/rotation operations. In this way, you’d have a mask this is adjustable in both width and height, but it doesn’t warp or stretch or scale oddly (of course, there would need to be some minimum size enforced, so the corner pieces wouldn’t overlap each other).

Perhaps this approach will work for you.

Brent