For clarity, I slightly oversimplified my previous discussion on efficiently rendering Flash in a 3D scene. The sticky bit is extracting transparency information from the Flash framebuffer so we can composite the overlay into the scene.
Flash does not give you direct access to its framebuffer. It does, with IViewObject::Draw, allow you to composite the Flash framebuffer onto a DIB section of your choice.
Remembering your Porter-Duff, composition of source over dest is:
Color = SourceColor * SourceAlpha + DestColor * (1 - SourceAlpha)
If the source color is premultiplied, you get:
Color = SourceColor + DestColor * (1 - SourceAlpha)
Assuming we want premultiplied color and alpha from Flash for efficient rendering in the 3D scene, applying the above requires solving for FlashAlpha and FlashColor:
RenderedColor = FlashColor * FlashAlpha + DestColor * (1 - FlashAlpha) RenderedColor = FlashColor * FlashAlpha + DestColor - DestColor * FlashAlpha RenderedColor - DestColor = FlashColor * FlashAlpha - DestColor * FlashAlpha RenderedColor - DestColor = FlashAlpha * (FlashColor - DestColor) FlashAlpha = (RenderedColor - DestColor) / (FlashColor - DestColor)
If FlashColor and DestColor are equal, then FlashAlpha is undefined. Intuitively, this makes sense. If you render a translucent black SWF on a black background, you can’t know the transparency data because all of the pixels are still black. This doesn’t matter, as I’ll show in a moment.
FlashColor is trivial:
RenderedColor = FlashColor * FlashAlpha + DestColor * (1 - FlashAlpha) RenderedColor - DestColor * (1 - FlashAlpha) = FlashColor * FlashAlpha FlashColor = (RenderedColor - DestColor * (1 - FlashAlpha)) / FlashAlpha
FlashColor is undefined if FlashAlpha is 0. Transparency has no color.
What do these equations give us? We know RenderedColor, since it’s the result of calling IViewObject::Draw. We have control over DestColor, since we configure the DIB Flash is drawn atop. What happens if we set DestColor to black (0)?
FlashColor = (RenderedColorOnBlack) / FlashAlpha
What happens if we set it to white (1)?
FlashColor = (RenderedColorOnWhite - (1 - FlashAlpha)) / FlashAlpha
Now we’re getting somewhere! Since FlashColor and FlashAlpha are constant, we can define a relationship between FlashAlpha and RenderedColorOnBlack and RenderedColorOnWhite:
(RenderedColorOnBlack) / FlashAlpha = (RenderedColorOnWhite - (1 - FlashAlpha)) / FlashAlpha RenderedColorOnBlack = RenderedColorOnWhite - 1 + FlashAlpha FlashAlpha = RenderedColorOnBlack - RenderedColorOnWhite + 1 FlashAlpha = RenderedColorOnWhite - RenderedColorOnBlack
So all we have to do is render the SWF on a white background and a black background and subtract the two to extract the alpha channel.
Now what about color? Just plug the calculated FlashAlpha into the following when rendering on black.
FlashColor = (RenderedColor - DestColor * (1 - FlashAlpha)) / FlashAlpha FlashColor = RenderedColorOnBlack / FlashAlpha
Since we want premultiplied alpha:
FlashColor = RenderedColorOnBlack
Now that we know FlashColor and FlashAlpha for the overlay, we can copy it into a texture and render the scene!