metafizzy / zdog

Flat, round, designer-friendly pseudo-3D engine for canvas & SVG
https://zzz.dog
10.37k stars 394 forks source link

Alpha mask #48

Open charlesr1971 opened 5 years ago

charlesr1971 commented 5 years ago

Please can you add the ability to create alpha masks, like:

new Zdog.Mask({ new Zdog.Shape({ addTo: illo, stroke: 20, ... }), linkedTo: [shape1, shape2...] });

Essentially, this would hide any objects behind the mask and that are linked to the mask.

At the moment, you can make a pseudo mask by creating a blocking shape of the same colour as the background shape, but when you rotate the scene, it is possible to see the blocking shape.

It would be great to be able hide any parts of objects that are behind the mask, that are linked to the mask, so I have added a:

linkedTo:

Attribute to the mask.

desandro commented 5 years ago

Add a 👍 reaction to this issue if you would like to see this feature added. Do not add +1 comments — They will be deleted.

Thanks for this feature request. This is feasible to do in both canvas and SVG, but its not exactly scalable. You need to manage groups of shapes and create separate rendering contexts.

charlesr1971 commented 5 years ago

@desandro Hi Desandro. I used to use masks in Adobe Flash. The mask is linked to an object or objects. At this point the mask turns from a coloured shape into a transparent area, that obscures any part of its linked shapes. So, the parts of the linked shapes that are not covered by the mask are still visible.

charlesr1971 commented 5 years ago

You can create some really spectacular spotlight effects with opacity masks!

jvgomg commented 5 years ago

Clipping masks would be great as I want to create a line drawing effect and think it can be achieved by transforming the paths out of the clipping shape. Something like this https://codepen.io/lukemeyrick/pen/eEyqVN

charlesr1971 commented 5 years ago

@jvgreenaway Love the rainbow animation. Very cool. Yes. I love clipping masks. It opens up a world of new possibilities!

mootari commented 5 years ago

Just spitballing here: Could this be solved by introducing layers and blendmodes? Each layer would essentially be a lightweight Illustration instance with its own detached canvas/context. The master/root Illustration would propagate all transforms to the layers and merge them in renderGraphCanvas(), right after onPrerender.

charlesr1971 commented 5 years ago

@mootari Are you saying that this can be achieved currently? Or would this methodology require some kind of core update.

mootari commented 5 years ago

Are you saying that this can be achieved currently?

@charlesr1971 Yup, albeit a bit unwieldy. Here's a basic example using canvas clip (but the idea also applies to blend modes): https://codepen.io/mootari/pen/gNZKwM

Note that things will get a lot more complicated if you want to use Zdog elements as masks. Also, I haven't looked into the SvgRenderer yet - that one might need some additional trickery to group paths inside the svg (and then apply clip paths to the group).

charlesr1971 commented 5 years ago

@mootari Wow. This is great work. What I want to do, is mask some ZDog spheres. So, I have 6 spheres [circular shapes] that rotate in the Z axis around an Anchor in the center of the canvas. When the spheres descend below 0 in the Y+ axis, I want them to be hidden. Essentially, I am trying to animate balls being juggled. I thought maybe I could use a semi circle as a mask, and the balls would disappear behind the semi circle? Do you think this would work with your approach? Thanks...

charlesr1971 commented 5 years ago

@mootari Looks like it works perfectly!

https://codepen.io/charles1971/pen/YoBXxP

Thanks very much for your help!

desandro commented 5 years ago

FWIW I used canvas compositing for masks in Shade & Shades and Fizzy bear

mootari commented 5 years ago

FWIW I used canvas compositing for masks in Shade & Shades and Fizzy bear

Please be aware that using illo.width and illo.height for canvas operations will break on HiDPI (Retina) displays. Instead illo.ctx.canvas.width and illo.ctx.canvas.height have to be used.

image