A multiply blend mode by itself is not sufficient because the image
being rgba multiplied typically has alpha transparency. The closest
approximation is to generate (offline, in software with getImageData)
an image per channel - rgbk - and to source-over blend the 'k' channel
and then additive blend the r/g/b channels with individual alpha. This
approximates the per-channel alpha values with nearly equivalent
results (I say nearly equivalent because some browsers do weird stuff
with gamma/colorspace conversion that completely breaks this.)

If it helps, you could think of this operation as a layer group in
photoshop. The first layer in the group is the source image, the
second layer is a solid color filled layer containing the rgba
'multiplier', in multiply mode, and then the layer group has a mask on
it that contains the source image's alpha information. Note that this
representation (a layer group with two layers and a mask) implies that
drawing an image this way requires multiple passes, which is highly
undesirable. My current fallback requires 4 passes, along with 4
texture changes and two blend state changes. Not wonderful.

RGBA multiplication dates back to early fixed-function graphics
pipelines. If a blend with globalAlpha and a premultiplied source is
represented like this:

result(r, g, b) = ( source-premultiplied(r, g, b) * globalAlpha ) + (
dest(r, g, b) * (1 - (source(a) * globalAlpha)) )

Then if you take a premultiplied color constant and use that as the
multiplier for your image (instead of a global alpha value - this is
the input to rgba multiplication, i.e. a 'vertex color'):

result(r, g, b) = ( source-premultiplied(r, g, b) *
rgba-multiplier-premultiplied(r, g, b) ) + ( dest(r, g, b) * (1 -
(source(a) * rgba-multiplier-premultiplied(a))) )

(Sorry if this is unclear, I don't have a math education)

So you basically take the global alpha multiplier and you go from that
to a per-channel multiplier. If you're using premultiplied alpha
already, this ends up being pretty straightforward... you just take a
color (premultiplied, like everything else) and use that as your
multiplier. You can multiply directly by each channel since the global
'alpha' part of the multiplier is already baked in by the
premultiplication step.

This is a really common primitive since it's so easy to implement, if
not entirely free - you're already doing that global alpha
multiplication, so you just introduce a different multiplier
per-channel, which is really trivial in a SIMD model like the ones
used in computer graphics. You go from vec4 * scalar to vec4 * vec4.

Text rendering is the most compelling reason to support this, IMO.
With this feature you can build glyph atlases inside 2d canvases
(using something like freetype, etc), then trivially draw colored
glyphs out of them without having to drop down into getImageData or
use WebGL. It is trivially expressed in most graphics APIs since it
uses the same machinery as a global alpha multiplier - if you're
drawing a premultiplied image with an alpha multiplier in hardware,
you're almost certainly doing vec4 * scalar in your shader. If you're
using the fixed-function pipeline from bad old 3d graphics, vec4 *
scalar didn't even exist - the right hand side was *always* another
vec4 so this feature literally just changed the constant on the right
hand side.

I harp on this feature since nearly every 2d game I encounter uses it,
and JSIL has to do it in software. If not for this one feature it
would be very easy to make the vast majority of ported titles Just
Work against canvas, which makes them more likely to run correctly on

On Fri, Aug 8, 2014 at 5:28 PM, Rik Cabanier <caban...@gmail.com> wrote:
> On Thu, Aug 7, 2014 at 7:11 PM, Katelyn Gadd <k...@luminance.org> wrote:
>> Sorry, in this context rgba multiplication refers to per-channel
>> multipliers (instead of only one multiplier for the alpha channel), so
>> that you can color tint images when drawing them. As mentioned, it's
>> used for fades, drawing colored text, and similar effects.
> I see. Any reason that this couldn't be done with a 'multiply' blend mode?
>> Premultiplication is a different subject, sorry if I confused you with
>> the similar language. There are past discussions about both in the
>> list archives.

Reply via email to