I’m a sucker for glow effects.  Whether I’m playing a video game with some neat bloom that makes a bright color bleed over other polygons or admiring a digital work of art in which the artist has applied some semi-transparent coloring around a light source, I’ve always appreciated what it adds to the image.<br/><br/>

It stands to reason that I would try my hand at doing this using HTML5 &lt;canvas&gt; and the neat little bag of tricks it provides.  Now that I’ve got a working prototype I thought I’d share it and describe how I rigged it up in case others are interested in trying it.  Everything I’m doing here is available in the stock version of the &lt;canvas&gt; API; no special plug-ins or third-party libraries are necessary (the script call to include javascript/canvas13.js is just a separate file where I organized my utility &lt;canvas&gt; calls). <br/><br/>

Before I continue I should point out that there are far easier ways to do a basic glow using &lt;canvas&gt; draw routines.  Everything from colored drop shadows to scaling and redrawing a shape repeatedly with progressively reduced alpha.  These techniques can be used with minimal code and will have you on your way much quicker than what I'm about to describe.  What they won't do is arbitrary, per-pixel glow calculations and make the glow bleed over occluding shapes, which is what I was after.<br/><br/>

<strong>You mean I can twiddle the pixels?  Oh my!</strong><br/><br/>

One of the really cool things about the &lt;canvas&gt; API is that it allows you to work with the pixels after you’ve done all of your drawing.  The following getImageData() call:<br/><br/>

yourPixelArray = yourHTML5DrawingContext.getImageData(0, 0, canvasWidth, canvasHeight);<br/><br/>

retrieves all the pixels from the 2D context yourHTML5DrawingContext and copies them to yourPixelArray as a byte array.  This allows you to read and write values for each component of each pixel.  Each pixel takes up four bytes, with its components being one byte apiece for red, green, blue, and alpha. This means advancing four elements in the array brings you to the next pixel.

With this kind of freedom, the frame buffer is your oyster.  In my case I decided to use four buffers to process and draw the glow, as follows:
<ul>
<li><strong>Frame buffer</strong> - The buffer the user sees.  The one to which everything else is drawn, and which contains the final image.  This is normally the only buffer that is visible.</li>
<li><strong>Glow color</strong> - This buffer is read to determine what color the glow pixels should be.  Only shapes that glow are drawn here.</li>
<li><strong>Glow output</strong> - Glow pixels are written here after they’re computed.  The contents of this buffer are composited onto the frame buffer.</li>
<li><strong>Glow parameter/occlusion</strong> - Glow parameters and shapes that should occlude a glowing object are written here.  Instead of colors, each "pixel" contains information about how the glow should be computed.  For each 32-bit pixel, this buffer contains:<br/><br/>
  <strong>Byte 1</strong> - Alpha value at which the first glow pixel away from the shape should start (0 - 255)<br/>
  <br/>
  <strong>Byte 2</strong> - The alpha of the underlying shape.  This is relevant because as this shape is fading from opaque to transparent, the alpha of its glow should be reduced accordingly (0 - 255).<br/>
  <br/>
  <strong>Byte 3</strong> - Glow distance in pixels (0 - 255).<br/>
  <br/>
  <strong>Byte 4</strong> - This is always 1.0 so that the data written to this buffer isn't altered by compositing operations.</li>
</ul>

<br/><br/>Once you’re done twiddling the bits of the pixels around, you can write the results back to your drawing context like so:<br/><br/>

yourHTML5DrawingContext.putImageData(yourPixelArray, 0, 0);<br/><br/>

This is a compositing operation, so it will write this over any existing image data already on the context (exactly how it does this will depend on your context’s composite operation setting). <br/><br/>

So how does my glow algorithm work mechanically?  First I draw the shape to the frame buffer so you’ll see it.  Then I draw it again to the glow color buffer so the algorithm knows what color to use.  I then draw it to the glow parameter/occlusion buffer so its glow parameters can be read, but here I’m substituting glow parameters for color data:<br/><br/>

glowOcclusionContext.fillStyle = "rgba(" + glowStartingAlpha256 + ", " + Math.floor(frameBufferContext.globalAlpha * 255) + ", " + glowDistanceInPixels + ", 1.0)";<br/><br/>

As I described above, with this call my shapes are now drawn in a color that will have significance for my glow pixel processing algorithm; when it needs to know the alpha of the glow pixel it's processing, it can read the alpha and distance from the red and blue pixel components of this buffer, respectively, and compute it accordingly. <br/><br/>

To see what’s going on with each buffer visually, I’ve set up a couple of example pages with all four buffers showing.  Normally I hide three of them since only the frame buffer is relevant, but seeing them all makes it clearer how the algorithm actually works. <br/><br/>

For an interactive page where you can control which parts of the glowing shapes are hidden, click <a href="/glow_buffer_demo.php">here</a>.<br/><br/>

For a more visually interesting page where you can see the glow color bleed onto the occluding shapes, click <a href="/glow_buffer_demo_2.php">here</a>.<br/><br/>
