Previous Entry: “Two-step text to path transformation”
Next Entry: “Why I won’t update Orbit Classic for Firefox 4”
In chapter 4 of “Interferences”, I’m using several layers stacked on top of each other with cumulative drop shadows. Of course I have written a Python extension for Inkscape to generate such cascading shadows automatically.
Let’s start with a simple example: five rounded rectangles stacked upon each other.
I want to add the impression of depth to this stack, and therefore add some drop shadows to these five layers. A simplistic attempt would be this: for each rectangle, I add a black copy which is slightly shifted, blurred and faded. I can define this operation as a filter: take the alpha channel of an object, smooth it with a Gaussian blur having a standard deviation of 1 % of the canvas size, shift the object 1 % of the canvas size to the right and 0.5 % to the bottom, and reduce the opacity to 75 % of the initial value.
This simple approach isn’t too convincing. Suppose the red rectangle hovers one inch above the topmost green rectangle, causing the shadow the red rectangle casts on this green rectangle to be shifted one inch to the right. If the distances between the rectangles and the white background are all equal, then this means that the red rectangles hovers five inches above the white background, and the shadow it casts on the white background should be shifted by five inches to the right, instead of just one.
Furthermore, we might want the shadow which the red rectangle casts on the background to be more blurry and more faded then the shadow cast on the first green rectangle.
I therefore use a more advanced model. To explain it, we temporarily restrict ourselves to just two rectangles:
The red rectangles casts a shadow…
…but I clip this shadow to the green rectangle:
To construct the shadow of the layer of the green rectangle, I take a black version of the green rectangle and the full shadow of the red rectangle:
Now I take this group of objects and apply my filter to them: I shift, blur and fade them, meaning that the already shifted, blurred and faded shadow of the red rectangle gets shifted, blurred and faded a second time.
While the shadow of the red rectangle on the green rectangle or the shadow of the green rectangle on the white background has an opacity of 75 %, the shadow of the red rectangle on the white background has an opacity of just 56.25 % (0.75 squared is 0.5625).
The next image shows the simplistic shadow on the left, the more advanced shadow on the right:
Unfortunately, there is a computational problem with this approach.
Blurring is a numerically costly operation, and fading, realized as a color matrix operation, is also costly. With five layers, we have to apply both operations 1 + 2 + 3 + 4 + 5 = 15 times, and in general, with n layers, we have to perform both operations (n+1)·n/2 times, and with complicated shapes, this is going to choke slower rendering engines.
To get convincing shadows, the most important part is that shadows are shifted with the correct amount. Since fading and blurring depend on more than just the virtual height of objects anyway (the distance of the light source, the reflectivity of the surroundings, including the backsides of our layers), we might get away with cumulating just the displacements, while applying blurring and fading just once for every shadow.
The next image compares the advanced version using cumulative blurring and fading besides cumulative shifting (left side) with a simplified version using just cumulative shifting (right side).
In the new version, the shadow of the red rectangle on the white background is a bit dark and hard, it is a bit too loud and attention grabbing and unsubtle. But perhaps we can get away with our simplified approach if we adjust the parameters: the next image compares the initial parameters with new parameters of a fade of 67 % (instead of 75 %) and a Gaussian blur with a standard deviation of 1.5 % (instead of 1 %):
For my taste and my purposes, that’s good enough.
As mentioned above, I wrote an extension which adds such shadows automatically. It works on all currently visible layers (which means that you can exclude layers from getting shadows by temporarily making them invisible), and treats all objects within one layer as having the same height. You can specify the amount of horizontal and vertical shifting (in pixels), the amount of blur (as standard deviation, measured in pixels) and the amount of fading.
Unzip the content of clshadows.zip within your Inkscape extension folder (which should be something like ~/
Unfortunately, some versions of Inkscape have a bit trouble updating their rendering of a document, so applying the extension might perhaps lead to the appearance of either incomplete or strange shadows, like this:
This is simply a matter of an outdated display: if you choose “View/
This is a known problem of Inkscape and not specific to my extension. If you are affected by this bug, unfortunately it means that you can’t use the live preview.
Another potential pitfall: blurring an object enlarges it, and a rendering engine tries to estimate how much larger it will become, and adjust the drawing area accordingly. Those estimates are rather dumb, and it’s possible to give rendering engines a hint how much larger the drawing area should become. Within the extension, I hardcoded an area increase of 20 %, which should be sufficient in most cases. In the following example, I changed this to an increase of the drawing area of just 5 % of the chosen object and set the blur standard deviation to 4 % of the canvas size:
The topmost red rectangle is especially problematic, since it is rather slim, compared to the total canvas size, and the filter region is therefore much too small. But since I have chosen such extreme values for the filter region and the blur, almost all shadows get cut. If you choose very large values for “blur”, and the shadows somehow look cut off, you can adjust this by opening “Filters/
Finally, the extension is not really intended to be applied two times to the same document. Especially, it would require a fundamental change in the code to make it possible to use two kinds of shadows within the same document.
Latest Skizzenblog Entry