Frizi
Frizi

Reputation: 2940

html canvas motion blur with transparent background

I just created a fancy canvas effect using cheap motion blur

ctx.fillStyle = "rgba(255,255,255,0.2)";
ctx.fillRect(0,0,canvas.width,canvas.height);

Now i want to do the same, but with transparent background. Is there any way to do something like that? I'm playing with globalAlpha, but this is probably a wrong way.

PS: Google really don't like me today

Upvotes: 5

Views: 6662

Answers (4)

hobberwickey
hobberwickey

Reputation: 6414

Here's a more performance friendly way of doing it, it requires an invisible buffer and a visible canvas.

buffer.save();
buffer.globalCompositeOperation = 'copy';
buffer.globalAlpha = 0.2;
buffer.drawImage(screen.canvas, 0, 0, screen.canvas.width, screen.canvas.height);
buffer.restore();

Basically you draw your objs to the buffer, which being invisible is very fast, then draw it to the screen. Then you replace clearing the buffer with copying the last frame onto the buffer using the global alpha, and globalCompositeOperation 'copy' to make the buffer into a semi-transparent version of the previous frame.

Upvotes: 5

Rob Evans
Rob Evans

Reputation: 6968

If you are keeping track of the entities on screen you can do this by spawning new entities as the mouse moves and then setting their alpha level in a tween down to zero. Once they reach zero alpha, remove the entity from memory.

This requires multiple drawing and will slow down rendering if you crank it up too much. Obviously the two-canvas approach is the simplest and cheapest from a render performance perspective but it doesn't allow you to control other features like making the "particles" move erratically or apply physics to them!

Upvotes: 0

Nathan Ostgard
Nathan Ostgard

Reputation: 8406

You can create an effect like this by using globalAlpha and two different canvas objects: one for the foreground, and one for the background. For example, with the following canvas elements:

<canvas id="bg" width="256" height="256"></canvas>
<canvas id="fg" width="256" height="256"></canvas>

You could copy draw both a background texture and a motion blurred copied of foreground like so:

bg.globalAlpha = 0.1;
bg.fillStyle = bgPattern;
bg.fillRect(0, 0, bgCanvas.width, bgCanvas.height);

bg.globalAlpha = 0.3;
bg.drawImage(fgCanvas, 0, 0);

Here is a jsFiddle example of this.

OP asked how to do this with an HTML background. Since you can't keep a copy of the background, you have to hold onto copies of previous frames, and draw all of them at various alphas each frame. Nostalgia: the old 3dfx Voodoo 5 video card had a hardware feature called a "t-buffer", which basically let you do this technique with hardware acceleration.

Here is a jsFiddle example of that style. This is nowhere near as performant as the previous method, though.

Upvotes: 2

Omiod
Omiod

Reputation: 11623

What you are doing in the example is partially clear the screen with a semi transparent color, but as it is, you will always gonna to "add" to the alpha channel up to 1 (no transparency).

To have this working with transparent canvas (so you can see what lies below) you should subtract the alpha value instead of adding, but I don't know a way to do this with the available tools, except running all the pixels one by one and decrease the alpha value, but this will be really, really slow.

Upvotes: 0

Related Questions