This article is compatible with the latest version of Silverlight.
Introduction
Element effects in Silverlight 2 were missing. This means that if you want to make your elements more attractive, you have to write your own effects. Silverlight.FX introduced a great number of effects and animations, which you can use. Nikhil Kothari has written a number of posts to show you the capabilities of this small but powerful framework.
In Silverlight 3 the Silverlight team had thought of implementing such effects. Thus, we had the pixel effects. Of course, you can use previous effect frameworks, but you'd better see the power of the built-in features.
Pixel Effects
Silverlight 3 beta 1 supports only two kinds of effects – the blur effect and the drop shadow effect. I will give you examples how to use these effects. However, the Silverlight team has implemented something that gives you much more power. You can implement your own effects and use them in your application. This process is not very simple, but I will try to explain you everything in details.
First, let’s get into the whole effect system of Silverlight. How is it constructed? Well actually it is done in a way that can be easily extended by adding more and more effects. Every object of type UIElement has a property, called Effect. It is of type Effect. All effects are all “in-place” effects in the sense that they output some modification of the pixel that is at the same location in the input texture as its destination in the output texture. It means that they just manipulate color but not position. How does this work? The way this works is that the Effect class defines a protected virtual method, called EffectMapping. The classes, which derive from the Effect class, have to override this method, which returns a GeneralTransform that takes a position and returns the post-effect corresponding position.
public abstract class Effect : DependencyObject |
{ |
protected Effect(); |
protected internal virtual GeneralTransform EffectMapping { get; } |
public static Brush ImplicitInput { get; } |
} |
Blur Effect
This effect is quite common. You may know this from your work with Photoshop or any other graphics software. It is built-in Silverlight, so you can use it very easily. Let’s create a simple application, which will demonstrate the usage of each of the effects. Our application will be called, Beeee (because I use an image with a bee to demonstrate the effect).
When you move the slider, the blur radius changes and the image becomes more and more blurred.
Cool, isn’t it? Let’s see how this is achieved. I will show you both the XAML way and the C# way. You may need to use either the first one or the second one in your projects.
<Image Source="images/bee.jpg" Stretch="Fill" Margin="10" x:Name="BeeImage"> |
<Image.Effect> |
<BlurEffect x:Name="BeeBlurEffect" Radius="1" /> |
</Image.Effect> |
</Image> |
private void SetEffects() |
{ |
BlurEffect effect = new BlurEffect(); |
effect.Radius = 10; |
|
BeeImage.Effect = effect; |
} |
Before using the effects in the code-behind you should include the System.Windows.Media.Effects namespace in your class file.
In this example I am using another great technique introduced in Silverlight 3 beta 1 – element to element binding. It allows you to bind a property of an object to a property of another object. Pretty cool and useful. In this example I have bound the Value property of the slider control to the Radius property of the BlurEffect object.
You can check the online demo.
Drop Shadow Effect
This is another common effect. It allows you to add shadow under your objects. It can help you to make your Silverlight applications more attractive to users. So let’s have a look at the demo application I have created.
You can change the blur radius and the shadow depth to manipulate the shadow. Here it is:
Here is the list of properties you can use to manipulate the shadow of an object.
- BlurRadius – manages the blur of the shadow
- ShadowDepth – manages the depth of the shadow, that is the distance between the shadow and the image
- Color – the color of the shadow
- Direction - an angle specifying the direction of the shadow
- Opacity – the opacity of the shadow
Here is the implementation both in the XAML way and the C# way as usual.
<Image Source="images/bee.jpg" Stretch="Fill" Margin="10" x:Name="BeeImage"> |
<Image.Effect> |
<DropShadowEffect x:Name="DropShadowEffect" BlurRadius="15" ShadowDepth="7" Color="DarkBlue" /> |
</Image.Effect> |
</Image> |
private void SetEffects() |
{ |
DropShadowEffect effect = new DropShadowEffect(); |
effect.BlurRadius = 10; |
effect.ShadowDepth = 5; |
|
BeeImage.Effect = effect; |
} |
You can check the online demo.
Implementing Custom Effects
I think this is the most interesting part of the article. Despite Silverlight has only two built-in effects, you can add your own effect. This process is not so simple but for the sake of the good application look, we can go through it.
In Silverlight, Shader Effects (a.k.a. Pixel Shaders) allow you to modify the rendered pixels of any UI Element before they are composited to the current view. They can be used to add effects to screen elements including shadows, blur, grayscale, redeye removal – pretty much anything you can accomplish by tweaking pixels using an algorithm. Normally, pixel shaders are done using the GPU (video card), but currently in Silverlight 3, Pixel Shaders are rendered using a software-based algorithm. This means that Pixel Shaders in Silverlight aren’t nearly as fast as they might be using the GPU.
In order to create a custom effect, you need to follow these steps. First, you need to install the latest version of DirectX SDK. You need the effects compiler (fxc.exe) from this SDK in order to be able to compile custom effects. Now you have to write your own effect using Microsoft's High-Level Shading Language (HLSL). This language is not very simple but it provides a way to manipulate images. Let’s write our first HLSL program and save it as WateryEffect.fx.
sampler2D input : register(S0); |
|
float4 main(float2 uv : TEXCOORD) : COLOR |
{ |
uv.y = uv.y + (sin(uv.y*100)*0.03); |
return tex2D( input , uv.xy); |
} |
Now, we have to compile this source using the effects compiler. So open the command prompt and enter the following command, which compiles FX files to PS.
fxc /T ps_2_0 /Fo WateryEffect.ps WateryEffect.fx
There is a tool, called Shazzam, which can help you to compile FX files. Here is the list of its features:
- Contains a HLSL editor.
- Open existing HLSL file. Save changes to file system if desired.
- Auto generates derived ShaderEffect class samples (VB and C#) for any valid HLSL snippet.
- Auto generates input controls to manipulate the shader registers.
- Contains sample images for instant viewing of shader effect.
- Supports importing custom user image.
- Rich color editing of C, C# and VB source.
If you don’t want to download and install any programs, you can check the Chris Hay’s Web Pixel Shader Compiler. It is a Silverlight application which does the compilation for you. You write your HLSL code and get the PS file after the compilation.
Tamir Khason has written a great post about pixel shader effects. You can check it and see how you can manipulate images using HLSL.
The next step is to include the PS file in your Silverlight project. You have to add it to your project in Visual Studio and change its Build Action to Resource. Now you have to create a class which will represent your effect. You have to derive from ShaderEffect class and to provide a default constructor which will initialize the effect.
public class WateryEffect : ShaderEffect |
{ |
public WateryEffect() |
{ |
PixelShader ps = new PixelShader(); |
ps.UriSource = new Uri("CustomEffects;component/effects/WateryEffect.ps", UriKind.Relative); |
|
this.PixelShader = ps; |
} |
} |
CustomEffects is the name of your assembly. In my project, the file WateryEffect.ps is in a folder, called effects. When you have used Resource as a build action, you have to specify the path to the file in the following way: component/{FILE_PATH_IN_VISUAL_STUDIO}.
Well, we now have our custom effect in Silverlight. Now we can use the same way as the previous effects.
<Image Source="images/bee.jpg" Stretch="Fill" Margin="10" x:Name="BeeImage"> |
<Image.Effect> |
<effects:WateryEffect /> |
</Image.Effect> |
</Image> |
Do not forget to include your effects namespace in the XAML.
xmlns:effects="clr-namespace:CustomEffects.effects" |
private void SetEffects() |
{ |
BeeImage.Effect = new WateryEffect(); |
} |
And here is our custom effect in action:
You can check the online demo.
Conclusion
The fact that Silverlight supports HLSL opens up a whole new world of possibilities for Silverlight developers. In beta 1 all these effects are not well optimized. Normally, pixel shaders are done using the GPU (video card), but currently in Silverlight, Pixel Shaders are rendered using a software-based algorithm. This means that Pixel Shaders in Silverlight aren’t nearly as fast as they might be using the GPU. I am sure this will be changed in the official release. Don't forget that you can apply effect not only to images, but also to every object of type UIElement. This is very powerful because you can achieve a great presentation, which your users will definitely like.
Source Code
You can download the source code of the examples and test it yourself.
References
- http://silverlight.net/learn/learnvideo.aspx?video=187303
- http://blogs.msdn.com/greg_schechter/archive/2008/05/12/more-details-on-how-effects-work.aspx
- http://dedjo.blogspot.com/2008/06/hlsl-pixel-shader-effects-tutorial.html
- http://www.wintellect.com/CS/blogs/jprosise/archive/2009/03/25/silverlight-3-s-new-pixel-shaders.aspx
- http://www.andybeaulieu.com/Home/tabid/67/EntryID/145/Default.aspx
- http://www.silverlightshow.net/tips/Using-Blur-and-DropShadow-effects-in-Silverlight-3.aspx