Masking & Clipping
Masking in Flash is one of those power features that lets you create effects that
otherwise wouldn't be possible. When you combine a mask with dynamic MovieClips,
the results can be really interesting.
Here is a Flash effect* produced with some clever masking:
To create this effect, we created an empty MovieClip named dots and placed
it on the bottom layer of our main stage. Next, we added some text on the layer
above it and converted this text layer to a mask layer to affect the dots beneath
it. We then created and exported for ActionScript another movieClip named dot
that has our shape animations growing and tinting the ellipse shape over its timeline
like so:
Since each dot will play as soon as it is created, we need to stretch out
the time it takes to add each diagonal strip of dots by using an onEnterFrame()
loop on our main stage. The code looks something like this:
The positioning algorithm in the addDots() function is actually a nested
loop if we think of the onEnterFrame() and xIndex incrementor
as our outer loop. This onEnterFrame handler will fire sequentially 47 times, each
time looping through its inner yIndex loop. The yIndex loop calculates
a diagonal line of up to 7 dots and adds them to our masked dots movieClip
if their location falls within the proper boundaries (Line 20). We also added an
onMouseDown() handler to let the user repeat the animation (Line
5 through Line 12).
Part 1 - Using Clips in Silverlight
The direct relation to this type of layer Mask in Silverlight would
be a Clipping region. So let's create a new Silverlight project
and rebuild this effect in Blend using Paths and Clips.
Afterward, we will look at another powerful masking technique Silverlight provides,
OpacityMasks.
To recreate the above effect using Clipping, create a new Silverlight project and
web hosting solution and modify Page.xaml as we've been doing every
lesson ( Set the dimensions, add a Loaded event handler, and change LayoutRoot to
a Canvas).
Inside LayoutRoot, you want to add empty Canvas tag named dots.
It is much easier to add the Clipping path in Blend, so right click
on Page.xaml and select Open in Expression Blend...
You could import a text design from Illustrator and convert it to a XAML path, but
we will use the default TextBlock in Blend to type in our message
and then convert the text to a Clipping Path like so:
Notice that I also selected my dots canvas so that the Clipping Path
would know which element to act upon.
Saving Page.xaml in Blend and reopening in Visual Studio gives
us a very long Clip definition inside our dots Canvas
that starts off something like this:
We will add the Loaded event handler in the code behind file once
we recreate the dot movieClip we used in our Flash example with our own
Silverlight User Control named dot.xaml.
Once you have created dot.xaml as a new User Control in your Silverlight
project and do the usual tweaks (remove background, width and height values while
converting LayoutRoot to a Canvas), add an Ellipse object inside LayoutRoot that
looks like this:
Animating the size and color of the ellipse using a Storyboard is much easier in
Blend, so go there and duplicate the shape animations we created in our Flash project:
I'm starting ellipse at a very small render scale and over the next 7 seconds,
I'm growing it to a larger scale and tweening its Fill colors.
If we look at dot.xaml to see the script for all these animations,
it would look something like this:
The code behind file dot.xaml.cs has our X and
Y public properties for easier positioning, a variable called milliseconds
that we'll use to customize how long each dot should wait before firing
the grow Storyboard we created above, and the fire() function
that will set the BeginTime for grow before starting it.
The finished dot.xaml.cs looks like this:
Since the Storyboard in dot.xaml gives us a way to programmatically
delay the BeginTime, the initialization and positioning logic we
need to add in Page.xaml is a bit more straightforward. The finished
Page.xaml code behind file looks like this:
The MouseLeftButtonDown event handler allows the user to repeat
the animation by clicking on the stage. All the real work is being handled by the
addDot() function that starts on Line 29. The positioning logic is the
same as we coded in Flash, only now the nested for loops are more
obvious. We programmatically set the milliseconds parameter to delay the
grow Storyboard in each progressive diagonal row of thumbs in Line 42 and
call the fire() method (Line 44) once that is set and the thumb
object has been added to our screen.
Here is the Silverlight result:
Part 2 - Silverlight Opacity Masks
Besides clipping paths on elements, Silverlight has another powerful type of masking
called OpacityMasks that can be applied to various visual elements.
Some of these more advanced features do not have a direct Flash correlation.
OpacityMasks can be defined not only with solid Shapes of color, but also transparency
Gradients that control the degree of Opacity; a very nice addition to masking. But
personally, my favorite feature of OpacityMasks is the ability to use an 24bit PNG
image as the OpacityMask and be able to control the degree of opacity at the pixel
level. Let's examine another Silverlight project that gives us an example of how
this works.
Before starting the project, I manipulated a photo in Photoshop to create a stylized
Black & White headshot against a transparent background. I then created a second
version of the headshot but only with those regions I wanted to also overlay with
a color gradient. My two finished .PNG files look like this:
I then created a new Silverlight Project and Hosting solution for these two images.
bwBase.png will serve as the background image and colorMask.png
will be applied to a Canvas with a gradient fill. After the usual tweaks and the
addition of these elements, Page.xaml looks like this:
Running the project right now will let us see what the OpacityMask is actually doing
to the gradient background of the colorBase (Line 10) canvas it is affecting:
However, the subtlety of this stacked approach is best highlighted if we also add
some dynamic elements to colorBase while also shifting the Scale of the gradient
while the mouse moves.
So as we did in Lesson 02, I will create a User Control that I can draw with a
MouseMove event that plays out its Storyboard and removes itself. I'll
call this User Control glow.xaml and it looks like this:
It was obviously easier to draw the Ellipse and create the grow Storyboard
in Expression Blend, so that's what I did. Notice we have also done the usual changes
we make to the User Control and LayoutRoot as well.
The code behind file glow.xaml.cs should also look familiar by
now:
We define X and Y to make positioning easier, fire the grow Storyboard
as soon as the User Control is Loaded, and then remove the User Control once grow
is Completed.
The positioning logic we add to Page.xaml.cs to draw the glow objects
on MouseMove should also look familiar by now:
And here is the finished Silverlight result:
Creative masking in Silverlight can be combined with programmatic visuals and XAML
Storyboards to create some very engaging experiences. In this lesson, we only scratched
the surface of what Silverlight Clipping and OpacityMasks can do. But the power
and adaptability of these techniques definitely deserve further attention.
In our next lesson, we will continue our exploration of Silverlight by looking at
Scale and Rotation techniques.
Additional Resources
*I first saw this effect in the book New Masters of Flash in the chapter by Jayson
Singe for Neon Sky. His technique required placing MovieClips by hand along several
dozen keyframes to create the effect. After some tinkering, I figured doing it all
in a positioning algorithm would make things easier. I've used variations of this
algorithm with students ever since.