[whatwg] CSS Filter Effects for Canvas 2D Context

Ashley Gullen ashley at scirra.com
Mon Jul 16 13:02:48 PDT 2012


I'd like to bring up this subject again especially now that first
implementations are starting to appear.

IMO the big use case here is games - the CSS filters are great for
interesting visual effects.  However there doesn't seem to be a way to use
them in canvas rendering, other than applying the effect to an entire
canvas. Games typically want to apply effects to individual objects
(meaning individual drawImage() calls), and there is no good way to do
this.  Stacking separate canvas elements is out of the question, because it
makes Z ordering with effects impossible.  Consider trying to overlay an
image with no effect on top of an image with an effect.  Also consider the
fact canvas has compositing modes like "lighter" and "destination-out", but
CSS filters do not provide these. This makes it impossible to combine CSS
filters and composite modes. An example is displaying an additive blended
explosion (typical in games) on top of an image with a blur CSS filter,
which seems to be impossible to achieve at all.

One way to define this is to specify that drawImage(), when passed another
canvas as a parameter, must take in to account the canvas' 'filter' CSS
property.  So to draw an image with a blur you'd render using an
intermediate canvas, e.g.

tempcanvascontext.drawImage(myimage, 0, 0);
tempcanvas.style.filter = "blur(10px)";
gamecanvascontext.drawImage(tempcanvas, 0, 0); // draws with blur

Another way would be just to add a 'filter' property to the 2D context,
e.g.:

gamecanvascontext.filter = "blur(10px)";
gamecanvascontext.drawImage(myimage, 0, 0);

This would also be extremely powerful if custom CSS shaders are also
supported, allowing for user-written effects in the canvas 2D context.

Effects should should apply to all drawing operations for consistency,
including lines, paths, rectangles and patterns.

I have no idea if this is easy for implementers (would appreciate comments
on that), but hopefully the CSS filter rendering can be recycled with
drawImage().

Another argument is that you should just use WebGL and write shaders for
advanced effects.  This is an option, but given that a filter effect can be
applied to an entire canvas, it seems a waste not to enable it for
individual draw calls, especially given the 2D context is considerably
easier and quicker to code for.

Ashley Gullen
Scirra.com


On 25 January 2012 16:26, Tab Atkins Jr. <jackalmage at gmail.com> wrote:

> On Wed, Jan 25, 2012 at 6:41 AM, David Geary <david.mark.geary at gmail.com>
> wrote:
> > On Tue, Jan 24, 2012 at 5:22 PM, Chris Marrin <cmarrin at apple.com> wrote:
> >> Adding filter functions to canvas would require you to re-render the
> items
> >> for every filter change and you'd have to animate it all yourself.
> >
> > Sure, but you must create a superfluous canvas for each set of images
> that
> > you animate, and invoke an entirely different technology to apply the
> > filter. You must  make sure that those superfluous canvases have
> > transparent backgrounds, no borders, and have the correct Z order so they
> > appear over, and not under, the primary canvas for the application. And
> I'm
> > sure there are other gotchas to this hybrid approach that don't
> immediately
> > come to mind.
> >
> > I'd much rather use the filtering underlying API and control the
> rendering
> > and animation myself.
>
> Yes, it's effectively creating an ad-hoc retained-mode API out of
> multiple <canvas> elements solely so it can apply filtering.
>
> (Using multiple backing canvases to sprite things is a reasonable
> performance hack, but I don't think it should be required for basic
> functionality.)
>
> ~TJ
>


More information about the whatwg mailing list