I know this is a long shot, but I wanted to use inkscape to create illustrations of wave propagation and interference. I thought it should be simple to represent peaks and troughs with white and black at some opacity level such that white on top of white would become brighter and black on top of black would become darker (constructive interference), while white on top of black or black on top of white would become neutral grey (destructive interference).
The problem I find is, the result of blending of two layers with partial transparency is always biased to emphasize the top layer. I can adjust the alpha values of the black and white layers to give grey for destructive interference, but only for a specific stacking order (e.g. black layer above white layer). When trying to illustrate several overlapping waves, it becomes effectively impossible to manage the stacking order such that black layers are above white layers at every point of overlap.
Inkscape seems to use the "Porter and Duff" blending equations described at http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending which seem to be standard. Looking at these, I don't see any nonzero values of rgba which will give the same output independent of the stacking order of the layers. So the only way to make alpha blending of two layers stacking order independent seems to be to modify this blending algorithm. Does anyone know where this algorithm is stored in the source code, and how hard it would be to modify?
Possible to change alpha blending algorithm?
Re: Possible to change alpha blending algorithm?
This kind of rendering is based on the rendering model defined in the SVG 1.1 specification (Inkscape uses SVG as native file format). If you need real blending modes, consider using SVG filter effects, not object or fill transparency:the result of blending of two layers with partial transparency is always biased to emphasize the top layer.
For more information, see these sections in the manual:
Filter Effects
Compositing Filter Primitives
… and related sections in the SVG 1.1 specification:
Rendering Model
Clipping, Masking and Compositing: Object and group opacity
Filter effects: Filter primitive ‘feBlend’
Re: Possible to change alpha blending algorithm?
Hi,
Do you have any svg to show ?
Try this :
stack n rect filled with a circular reflective gradient that goes from black to white (add some nodes to make it look like a sine and not triangular).
Opacity of nth rectangle should be 1/n => 100% for rect1 (at the bottom), 50% for rect2, 33% for rect3, 25% for rect4
Do you have any svg to show ?
Try this :
stack n rect filled with a circular reflective gradient that goes from black to white (add some nodes to make it look like a sine and not triangular).
Opacity of nth rectangle should be 1/n => 100% for rect1 (at the bottom), 50% for rect2, 33% for rect3, 25% for rect4
Re: Possible to change alpha blending algorithm?
Vince, I tried what you suggest but I don't think it quite gets at the issue I'm having. I don't want to have to manage which layer has what transparency level in the stack, I just want to have overlapping layers blend in a way that doesn't depend on the stacking order.
The filter effects seem like the key to do this. However, I'm still having trouble. I thought the composite arithmetic mode would be perfect, because what I want is basically an averaging of all the layers. Using values of K1=0, K2=0.5, K3=0.5 and K4=0 should achieve this I thought. For two layers only it does work: if I have a solid gray background of i1=0.5 (no filter), and a black rectangle of i2=0 on top of it, with filter applied I get 0.5*0.5 + 0.5*0 = 0.25, a dark grey. And if I have a white rectangle on this background I get 0.5*1+0.5*0.5 = 0.75, a light grey. So far so good.
But when I attempt to overlap the white and black rectangles, I get the same kind of problem I had with rgba. If the black rectangle is on top, the overlap is darker than 0.5. If the white rectangle is on top, the overlap is lighter than 0.5. In the documentation I don't see anything addressing how more than 2 layers are handled, but apparently it's not intuitive since applying the same equation to the 0.25 and 0.75 obtained before should get me back to 0.5. I don't think it's an issue of the background being counted twice as the documentation warns, since all the layers are fully opaque. I don't see any discussion of how more than two layers are handled in the composite arithmetic filter. Any ideas?
Edit: I see what's happening now. If I have, for example, a stack of 0.5, 0, and 1 overlapping, it first averages 0.5 and 0 (=0.25), then averages that with the next layer (=.625). So what I really want is to average all the layers at once, but what I get is a nested averaging where the average of the bottom two layers is averaged with the next layer up, that result is averaged with the next layer up, etc.
http://imageshack.us/photo/my-images/846/filteroverlap.png
I'll have to think about whether there's a way to make this work...
The filter effects seem like the key to do this. However, I'm still having trouble. I thought the composite arithmetic mode would be perfect, because what I want is basically an averaging of all the layers. Using values of K1=0, K2=0.5, K3=0.5 and K4=0 should achieve this I thought. For two layers only it does work: if I have a solid gray background of i1=0.5 (no filter), and a black rectangle of i2=0 on top of it, with filter applied I get 0.5*0.5 + 0.5*0 = 0.25, a dark grey. And if I have a white rectangle on this background I get 0.5*1+0.5*0.5 = 0.75, a light grey. So far so good.
But when I attempt to overlap the white and black rectangles, I get the same kind of problem I had with rgba. If the black rectangle is on top, the overlap is darker than 0.5. If the white rectangle is on top, the overlap is lighter than 0.5. In the documentation I don't see anything addressing how more than 2 layers are handled, but apparently it's not intuitive since applying the same equation to the 0.25 and 0.75 obtained before should get me back to 0.5. I don't think it's an issue of the background being counted twice as the documentation warns, since all the layers are fully opaque. I don't see any discussion of how more than two layers are handled in the composite arithmetic filter. Any ideas?
Edit: I see what's happening now. If I have, for example, a stack of 0.5, 0, and 1 overlapping, it first averages 0.5 and 0 (=0.25), then averages that with the next layer (=.625). So what I really want is to average all the layers at once, but what I get is a nested averaging where the average of the bottom two layers is averaged with the next layer up, that result is averaged with the next layer up, etc.
http://imageshack.us/photo/my-images/846/filteroverlap.png
I'll have to think about whether there's a way to make this work...
Re: Possible to change alpha blending algorithm?
After messing with this for a long time, I finally got it. In case anyone else is going insane trying to figure out the composite arithmetic filter, here are some details I figured out through trial-and-error.
For the RGB channels, the pixel values i1 and i2 (from the equation K1 × i1 × i2 + K2 × i1 + K3 × i2 + K4) refer to values between 0 (=RBG 0) and 1 (=RGB 255) multiplied by the alpha value ("pre-multiplied") where alpha is also from 0 (transparent) to 1 (opaque). The result of the equation then gives the final RGB value, independent of the final alpha value (no need to un-multiply).
The alpha channel doesn't involve pre-multiplication, but was even more confusing for me until I realized how to properly interpret a non-opaque rgba result. I had been applying the filter, calculating what the rgba should have been, then making a rectangle and setting it to this value to see whether it was the same as the blended region. The problem was, I was comparing with the rectangle against the white background. When alpha was less than 1, the background caused the rectangle to be too light compared to the blending result. It didn't register for me initially that a blending result with some transparency should be equivalent to a rectangle of that rgba value against the same background as was used in the blending filter, not against the white document background.
Once I understood all this, I was able to get what I wanted by using K1=0, K2=1, K3=1, and K4=-0.5. I set the background to neutral grey (rgb=0.5,1) and represented peaks and troughs with small deviations like (.45,1) and (.55,1). With K2 and K3 equal to 1 instead of 0.5, the calculation sums rather than averages layers, and the -0.5 offset means that each layer adds or subtracts the deviation from 0.5 rather than the absolute value. So a 0.45 layer on top of a 0.55 layer cancels to give a 0.5 result regardless of stacking order (as long as stacks of more than (0.5/deviation) in a row don't occur, since the range of values is capped at 0 and 1).
Quite a long way to go for what seemed like a simple goal, but at least I ended up with something that works. Thanks for the suggestion to use filter effects and the links.
Edit: Didn't take long to find a new problem. The filter seems to only be applicable as a rectangle that covers the entire selection regardless of shape. I need some way to exclude the regions under the filter which don't contain any visible objects, because the filter is treating this region as an extra alpha=0 layer in the calculation and making a dark grey box around any shape that I apply the filter to.
Edit2: Solved the last problem by adding a flood effect to the filter with (rgb=0.5,a=1) and then a merge effect to merge the flood result with the source graphic. It looks like this just replaces the transparent parts with solid grey. The output of the merge is then composite blended with the background using the K values above. Here's an example of the result:
For the RGB channels, the pixel values i1 and i2 (from the equation K1 × i1 × i2 + K2 × i1 + K3 × i2 + K4) refer to values between 0 (=RBG 0) and 1 (=RGB 255) multiplied by the alpha value ("pre-multiplied") where alpha is also from 0 (transparent) to 1 (opaque). The result of the equation then gives the final RGB value, independent of the final alpha value (no need to un-multiply).
The alpha channel doesn't involve pre-multiplication, but was even more confusing for me until I realized how to properly interpret a non-opaque rgba result. I had been applying the filter, calculating what the rgba should have been, then making a rectangle and setting it to this value to see whether it was the same as the blended region. The problem was, I was comparing with the rectangle against the white background. When alpha was less than 1, the background caused the rectangle to be too light compared to the blending result. It didn't register for me initially that a blending result with some transparency should be equivalent to a rectangle of that rgba value against the same background as was used in the blending filter, not against the white document background.
Once I understood all this, I was able to get what I wanted by using K1=0, K2=1, K3=1, and K4=-0.5. I set the background to neutral grey (rgb=0.5,1) and represented peaks and troughs with small deviations like (.45,1) and (.55,1). With K2 and K3 equal to 1 instead of 0.5, the calculation sums rather than averages layers, and the -0.5 offset means that each layer adds or subtracts the deviation from 0.5 rather than the absolute value. So a 0.45 layer on top of a 0.55 layer cancels to give a 0.5 result regardless of stacking order (as long as stacks of more than (0.5/deviation) in a row don't occur, since the range of values is capped at 0 and 1).
Quite a long way to go for what seemed like a simple goal, but at least I ended up with something that works. Thanks for the suggestion to use filter effects and the links.
Edit: Didn't take long to find a new problem. The filter seems to only be applicable as a rectangle that covers the entire selection regardless of shape. I need some way to exclude the regions under the filter which don't contain any visible objects, because the filter is treating this region as an extra alpha=0 layer in the calculation and making a dark grey box around any shape that I apply the filter to.
Edit2: Solved the last problem by adding a flood effect to the filter with (rgb=0.5,a=1) and then a merge effect to merge the flood result with the source graphic. It looks like this just replaces the transparent parts with solid grey. The output of the merge is then composite blended with the background using the K values above. Here's an example of the result:
Re: Possible to change alpha blending algorithm?
I see what you mean now, that is basically what I want to do except I want to be able to overlap many such rings to show propagation of wavefronts of arbitrary shape. I'm not sure if there's an automated/systematic way to apply this to a large number of layers? Maybe interpolation between the bottom and top layers to produce all the intermediate transparency levels...
Here's a better example of the sort of thing I'm going for, using the filter method figured out above. So far this is just using stroke but gradients should look smoother.
Here's a better example of the sort of thing I'm going for, using the filter method figured out above. So far this is just using stroke but gradients should look smoother.