Learning SVG: lesson 2

Innershadow

After I successfully mastered the art of dropshadow, what next?

Looking at Photoshop layer styles, the next thing on the list is innershadow. Yawn. More Gaussian blur and… wait, it’s actually more complicated than I first thought.

Blurring a shape results in a new shape that’s more opaque in the center and fades away towards the edge. Innershadow is the exact opposite. The solution, it turns out, is to subtract the blurred opacity from the original shape. A picture is better than a thousand words:


The idea is, take the original image (first row), blur the alpha mask (white in the second row), subtract the blurred alpha (black in the same row), take the difference (third row), composite it on top of the original image (last row). Code:

<svg	xmlns="http://www.w3.org/2000/svg"
	xmlns:xlink="http://www.w3.org/1999/xlink"
	width="250" height="90">
	<def>
		<linearGradient id="greenBg" x1="0" y1="0" x2="0" y2="100%">
			<stop offset="0" stop-color="#7d9a94"/>
			<stop offset="1" stop-color="#aab9b4"/>
		</linearGradient>
		<pattern id="checker" patternUnits="userSpaceOnUse"
				x="0" y="0" width="20" height="20">
			<rect x="0" y="0" height="20" width="20" fill="#aaaaaa"/>
			<rect x="0" y="0" height="10" width="10" fill="#999999"/>
			<rect x="10" y="10" height="10" width="10" fill="#999999"/>
		</pattern>
		<g id="obj">
		<path d="M 40.342584,6.7575912 49.849205,26.134167 71.215132,29.187812
			55.724621,44.216837 59.422867,65.480669 40.342583,55.392542
			21.262297,65.480668 24.960545,44.216837 9.470034,29.18781
			30.83596,26.134167 40.342584,6.7575912 z"/>
		<circle cx="110" cy="40" r="30"/>
		<rect x="160" y="15" width="50" height="50"/>
		</g>
		<filter id="innershadow" x0="-50%" y0="-50%" width="200%" height="200%">
			<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/>
			<feOffset dy="3" dx="3"/>
			<feComposite in2="SourceAlpha" operator="arithmetic"
					k2="-1" k3="1" result="shadowDiff"/>
			<feFlood flood-color="black" flood-opacity="1"/>
			<feComposite in2="shadowDiff" operator="in"/>
			<feComposite in2="SourceGraphic" operator="over"/>
		</filter>
	</def>

	<rect x0="0" y0="0" width="250" height="90" fill="url(#checker)"/>
	<use xlink:href="#obj" style="fill:url(#greenBg);stroke:none;filter:url(#innershadow)"/>
</svg>

The main thing is shown in bold. Visually, this kind of sharp-edged inner shadow describes holes on the plane, with the edges casting shadows beneath them - why am I explaining this?

The <feFlood> is there if I wanted the shadow to be some other color/opacity. Curiously, I thought putting flood-color="black" flood-opacity="1" there would have no effect here because it’s basically replacing black with black-but with it the shadow is visibly darker. I must have misunderstood the <feComposite> above it (see, I’m new at this).

Naturally, if I can drop a black shadow from top left, I can drop a white shadow (pardon the oxymoron) from bottom right; just change the offset and the flood-fill color, i.e.

			<feOffset dy="-2" dx="-2" />
			<feComposite in2="SourceAlpha" operator="arithmetic"
					k2="-1" k3="1" result="shadowDiff"/>
			<feFlood flood-color="white" flood-opacity="1"/>

like this:

Visually, this kind of sharp-edged inner white shadow describes … ok it doesn’t quite look like anything, yet. Just wait.

Bevel

Although the white shadow by itself doesn’t quite look like anything, when combined with the black one, we got the bevel effect:

		<filter id="innerbevel" x0="-50%" y0="-50%" width="200%" height="200%">
			<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/>
			<feOffset dy="-1" dx="-1"/>
			<feComposite in2="SourceAlpha" operator="arithmetic"
					k2="-1" k3="1" result="hlDiff"/>
			<feFlood flood-color="white" flood-opacity=".7"/>
			<feComposite in2="hlDiff" operator="in"/>
			<feComposite in2="SourceGraphic" operator="over" result="withGlow"/>

			<feOffset in="blur" dy="3" dx="3"/>
			<feComposite in2="SourceAlpha" operator="arithmetic"
					k2="-1" k3="1" result="shadowDiff"/>
			<feFlood flood-color="black" flood-opacity="1"/>
			<feComposite in2="shadowDiff" operator="in"/>
			<feComposite in2="withGlow" operator="over"/>
		</filter>

like this:

Now there are two ways to look at it: either it’s an embossing and light comes from bottom right, or it’s an engraving and light is from the other direction. Your pick. I’m not sure if this is because my inadequate skill, or rather it’s something intrinsic, but I do remember having the same problem looking at the photos of Moon craters: sometimes they suddenly appear to be bulging up. Is there a word for this phenomenon?

The above is similar to Photoshop inner bevel filter. With some modification, the outerbevel can be done, too:

		<filter id="outerbevel" x0="-50%" y0="-50%" width="200%" height="200%">
			<feMorphology in="SourceAlpha" operator="dilate" radius="1"/>
			<feGaussianBlur stdDeviation="1" result="blur"/>

			<feOffset dy="1" dx="1"/>
			<feComposite in2="SourceAlpha" operator="arithmetic"
					k2="1" k3="-1" result="hlDiff"/>
			<feFlood flood-color="white" flood-opacity=".7"/>
			<feComposite in2="hlDiff" operator="in"/>
			<feComposite in2="SourceGraphic" operator="over" result="withGlow"/>

			<feOffset in="blur" dy="-1" dx="-1"/>
			<feComposite in2="SourceAlpha" operator="arithmetic"
					k2="1" k3="-1" result="shadowDiff"/>
			<feFlood flood-color="black" flood-opacity="1"/>
			<feComposite in2="shadowDiff" operator="in"/>
			<feComposite in2="withGlow" operator="over"/>
		</filter>

Alas, all renders are not created equal. Gimp (the software, duh) thinks it looks like this:

white Firefox thinks it looks like

I tend to side with Firefox on this one. Either way, though, the effect is less ambiguous than the inner bevel.

In principle, one should be able to make two Gaussians with different sigmas, and use the difference of those to generate the edge effects, thus handling both the inner and outer bevel at the same time.
Just a thought, haven’t tried it yet.

If we take both inner and outer bevel and stack them together (also flip the light direction for the inner one),
we get a crude version of pillow emboss:

Again, this is taken from screen shot of Firefox. Gimp renders the outer part way too dark.

I think I’ver learned enough today to call this a sastifactory lesson 2. Go me.

Advertisements
  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: