- From: Katelyn Gadd <kg@luminance.org>
- Date: Fri, 8 Aug 2014 19:54:12 -0700
- To: Rik Cabanier <cabanier@gmail.com>
- Cc: Justin Novosad <junov@google.com>, WHAT Working Group <whatwg@whatwg.org>, Robert O'Callahan <robert@ocallahan.org>
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 mobile. On Fri, Aug 8, 2014 at 5:28 PM, Rik Cabanier <cabanier@gmail.com> wrote: > > > > On Thu, Aug 7, 2014 at 7:11 PM, Katelyn Gadd <kg@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. >>
Received on Saturday, 9 August 2014 02:55:20 UTC