0
votes

I am currently working on a freehand drawing application where I need to support multiple background textures. For example, a paper-like texture or an image. The drawing on both background textures should behave identically.

It works great when using one or the other texture as a starting point for the drawing, i.e. blend all incoming strokes directly with the background texture.

However, I want to take a different approach: Drawing all strokes to an initially transparent layer, then blending this layer with the selected background. This has the advantage that the drawing is independent and separated from the background. For example I could blend the whole drawing with a different background without having to blend all strokes with this background directly.

The problem is: Depending on the color of the transparent layer, the outcome of the blended image (background + "stroke layer") looks totally different. For example, with rgba values, setting the transparent layer to transparent white (1,1,1,0) yields much brighter colors than setting the layer to transparent black (0,0,0,0). This makes sense because we have to blend the strokes with the transparent color. What I basically want to have is a "neutral" transparency. The strokes on this transparent layer should interact only with the background image, not with the transparent layer. The transparent layer should only be used to store the drawn strokes.

My question: Is this somehow possible? I can't find a way to solve this. The problem is that the transparent layer (which is just a texture with a transparent color) must have a color and incoming strokes must be blended with this color. Is there a way to avoid this somehow?

1

1 Answers

0
votes

I figured out how to do it:

For blending two transparent colors, the Porter-Duff algorithm can be used. It is described here for example. Blending destination and source color can be done this way:

inline float4 porter_duff_blending(float4 dest, float4 source) {
    float alpha = source.a;
    float inv_alpha = 1 - alpha;
    float blend_alpha = alpha + inv_alpha * dest.a;
    float4 blend_color  = (1.0 / blend_alpha) * ((alpha * source) + (inv_alpha * dest.a * dest));
    blend_color.a = blend_alpha;
    return blend_color;
};

This allows to have the drawing in a separate transparent layer which can be applied to different backgrounds.