Pixel Shader Effects

Microsoft Silverlight will reach end of support after October 2021. Learn more.

Pixel shader effects allow you to add effects, such as grayscale, red eye removal, pixel brightness, and shadows, to rendered objects. Pixel shader effects use an algorithm to alter how pixels are displayed. For example, the following illustration shows a drop shadow applied to a button.

Button with a DropShadow applied to it.

You can use the pixel shader effects included with the Silverlight runtime or you can create your own.

NoteNote:

Pixel shader effects in Silverlight are rendered in software. Any object that applies an effect will also be rendered in software. Performance degrades the most when effects are applied to large visuals or when properties of an effect are animated. Therefore, you should be careful when you use effects and thoroughly test them to make sure that your users are getting the experience you expect.

This topic contains the following sections.

  • Drop Shadow and Blur
  • Applying Multiple Effects to an Object
  • Creating a Custom Pixel Shader Effect

Drop Shadow and Blur

There are two pixel shader effects included with the Silverlight runtime: DropShadowEffect and BlurEffect. The examples in this section use DropShadowEffect and demonstrate the following capabilities:

  • How to use XAML to apply that effect to an object.

  • How to use a Style to apply the effect to one or more objects.

  • How to use code to apply the effect to an object.

  • How to animate the properties of an effect.

NoteNote:

Working with BlurEffect is similar to the DropShadowEffect. For more information, see BlurEffect.

The following example shows how to use XAML to apply a DropShadowEffect to a Button.

Run this sample

<StackPanel>
    <Button Content="Drop Shadow Under Me" Width="200" Margin="10">
        <Button.Effect>

            <!-- The DropShadowEffect has several important properties that
           determine characteristics of the drop shadow: 
         - Color: Specifies the color of the drop shadow. Default is black.
         - ShadowDepth: Specifies how far displaced the shadow is from the object
           casting the shadow. Default is 5.
         - Direction: Specifies in what direction the shadow is cast from the object. 
           It is an angle between 0 and 360 with 0 starting on the right hand side 
           and moving counter-clockwise around the object. The value of 320 in this 
           example casts the shadow on the lower right hand side of the button. The default
           is 315.
         - BlurRadius: Specifies how blurry the shadow is. The range is between 0 and 1 with 1
           being the softest. Default is 5. 
         - Opacity: Specifies how transparent the shadow is. The range is between 0 
           and 1 with 1 being fully opaque and 0 fully transparent (not visible). The
           default is 1. -->
            <DropShadowEffect Color="Black" Direction="320" ShadowDepth="25" 
             BlurRadius="5" Opacity="0.5" />
        </Button.Effect>
    </Button>
</StackPanel>

The following example shows how to use a Style to apply a DropShadowEffect to a Button.

Run this sample

<StackPanel x:Name="LayoutRoot" Background="White">
    <StackPanel.Resources>
        <Style x:Name="buttonStyle" TargetType="Button" >
            <Style.Setters>
                <Setter Property = "Effect" >
                    <Setter.Value>
                        <DropShadowEffect Color="Black" Direction="320"  
                         ShadowDepth="25" BlurRadius="5" Opacity="0.5" />

                    </Setter.Value>
                </Setter>
            </Style.Setters>
        </Style>
    </StackPanel.Resources>
    <Button Width="200" Height="30" Style="{StaticResource buttonStyle}" 
            Margin="20" Content="Drop Shadow Under Me" />
</StackPanel>

The following example shows how to use code to apply a DropShadowEffect to a Button when it is clicked.

Run this sample

<StackPanel>
    <Button Click="ApplyDropShadow" Width="200" Margin="20" 
            Content="Click!" />
</StackPanel>
Private Sub ApplyDropShadow(ByVal sender As Object, ByVal e As RoutedEventArgs)

    Dim myButton As Button = CType(sender, Button)

    ' Initialize a new DropShadowEffect that will be applied
    ' to the Button.
    Dim myDropShadowEffect As DropShadowEffect = New DropShadowEffect

    ' Set the color of the shadow to Black.
    Dim myShadowColor As Color = New Color
    myShadowColor.A = 255

    ' Note that the alpha value is ignored by Color property. 
    ' The Opacity property is used to control the alpha.
    myShadowColor.B = 50
    myShadowColor.G = 50
    myShadowColor.R = 50
    myDropShadowEffect.Color = myShadowColor

    ' Set the direction of where the shadow is cast to 320 degrees.
    myDropShadowEffect.Direction = 320

    ' Set the depth of the shadow being cast.
    myDropShadowEffect.ShadowDepth = 25

    ' Set the shadow softness to the maximum (range of 0-1).
    myDropShadowEffect.BlurRadius = 6

    ' Set the shadow opacity to half opaque or in other words - half transparent.
    ' The range is 0-1.
    myDropShadowEffect.Opacity = 0.5

    ' Apply the effect to the Button.
    myButton.Effect = myDropShadowEffect
End Sub
private void ApplyDropShadow(object sender, RoutedEventArgs e)
{
    Button myButton = (Button)sender;


    // Initialize a new DropShadowEffect that will be applied
    // to the Button.
    DropShadowEffect myDropShadowEffect = new DropShadowEffect();

    // Set the color of the shadow to Black.
    Color myShadowColor = new Color();
    myShadowColor.A = 255; // Note that the alpha value is ignored by Color property. 
    // The Opacity property is used to control the alpha.
    myShadowColor.B = 50;
    myShadowColor.G = 50;
    myShadowColor.R = 50;

    myDropShadowEffect.Color = myShadowColor;

    // Set the direction of where the shadow is cast to 320 degrees.
    myDropShadowEffect.Direction = 320;

    // Set the depth of the shadow being cast.
    myDropShadowEffect.ShadowDepth = 25;

    // Set the shadow softness to the maximum (range of 0-1).
    myDropShadowEffect.BlurRadius = 6;

    // Set the shadow opacity to half opaque or in other words - half transparent.
    // The range is 0-1.
    myDropShadowEffect.Opacity = 0.5;

    // Apply the effect to the Button.
    myButton.Effect = myDropShadowEffect;
}

The following example shows how to animate the ShadowDepth and BlurRadius properties of the DropShadowEffect to make it appear like the Button is lifting off of the screen after it is clicked.

Run this sample

<StackPanel>
    <StackPanel.Resources>
        <Storyboard x:Name="myStoryboard">

            <!-- Animate shadow depth of the effect. -->
            <DoubleAnimation
           Storyboard.TargetName="myDropShadowEffect"
           Storyboard.TargetProperty="ShadowDepth"
           To="30" Duration="0:0:0.5"
           AutoReverse="True" />

            <!-- Animate shadow BlurRadius of the effect. As 
               the Button appears to get farther from the shadow,  
               the shadow blurs. -->
            <DoubleAnimation
           Storyboard.TargetName="myDropShadowEffect"
           Storyboard.TargetProperty="BlurRadius"
           To="10" Duration="0:0:0.5"
           AutoReverse="True" />

            <!-- Animate ScaleX of button. -->
            <DoubleAnimation
           Storyboard.TargetName="myScaleTransform"
           Storyboard.TargetProperty="ScaleX"
           To="1.5" Duration="0:0:0.5"
           AutoReverse="True" />

            <!-- Animate ScaleY of button. -->
            <DoubleAnimation
           Storyboard.TargetName="myScaleTransform"
           Storyboard.TargetProperty="ScaleY"
           To="1.5" Duration="0:0:0.5"
           AutoReverse="True" />

            <!-- Move button in the X direction. -->
            <DoubleAnimation
           Storyboard.TargetName="myTranslateTransform"
           Storyboard.TargetProperty="X"
           To="-30" Duration="0:0:0.5"
           AutoReverse="True" />

            <!-- Move button in the Y direction. -->
            <DoubleAnimation
           Storyboard.TargetName="myTranslateTransform"
           Storyboard.TargetProperty="Y"
           To="-30" Duration="0:0:0.5"
           AutoReverse="True" />

        </Storyboard>

    </StackPanel.Resources>
    <Button Content="Click!" Click="StartAnimation" Width="200"
            Margin="60">
        <Button.Effect>
            <DropShadowEffect x:Name="myDropShadowEffect" />
        </Button.Effect>
        <Button.RenderTransform>
            <TransformGroup>
              <TranslateTransform x:Name="myTranslateTransform" />
              <ScaleTransform x:Name="myScaleTransform" />
            </TransformGroup>
        </Button.RenderTransform>
    </Button>
</StackPanel>
Private Sub StartAnimation(ByVal sender As Object, ByVal args As RoutedEventArgs)
    myStoryboard.Begin()
End Sub
private void StartAnimation(object sender, RoutedEventArgs args)
{
    myStoryboard.Begin();
}

Applying Multiple Effects to an Object

You can apply only one effect directly to an element at a time. For example, you cannot apply a BlurEffect and a DropShadowEffect to the same element directly. However, you can apply an effect to the container of an element and therefore apply the effect to the nested child. In the following example, a DropShadowEffect is applied to a Button and a BlurEffect is applied to a Grid that contains the Button. This creates a blurry button with a drop shadow.

NoteNote:

Applying multiple effects can have adverse effects on the performance of your application.

Run this sample

<Grid>

    <!-- Apply a Blur effect to the container of the Button. -->
    <Grid.Effect>
        <BlurEffect Radius="10" />
    </Grid.Effect>
    <Button Content="Drop Shadow Under Me" Width="200" Height="30" Margin="10">
        <Button.Effect>
            <DropShadowEffect Color="Black" Direction="320" ShadowDepth="25" 
             BlurRadius="5" Opacity="0.5" />
        </Button.Effect>
    </Button>
</Grid>

Creating a Custom Pixel Shader Effect

You can create your own custom pixel shader effects. The following example shows an image with and without a custom pixel shader effect applied to it.

Run this sample

To create your own pixel shader effect, you need to do the following:

  1. Create a pixel shader by using the High-Level Shader Language (HLSL) and compile it into a .ps file.

    HLSL is part of the DirectX SDK. To compile .ps files, you can use the fxc command-line tool provided with the DirectX SDK or another tool like Shazzam, which gives you a convenient UI for working with fxc.

  2. Derive your custom effect from the ShaderEffect class and set the PixelShader property of your custom pixel shader effect to your .ps file.

    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Effects;
    using System;
    
    namespace PixelShaderSample
    {
    
        public class MyPixelInvertedEffect : ShaderEffect
        {
    
            public MyPixelInvertedEffect()
            {
    
                // Include your project name and .ps file.
                Uri u = new Uri(@"/PixelShaderSample;component/InvertColors.ps", UriKind.Relative);
    
                // Set the PixelShader of the custom shader effect to use your custom .ps file.
                PixelShader myPixelShader = new PixelShader();
                myPixelShader.UriSource = u;
                this.PixelShader = myPixelShader;
    
            }
        }
    }
    

3. Apply the custom pixel shader effect to your object (in this case an image).

    <UserControl x:Class="PixelShaderSample.MainPage"
    xmlns:shader="clr-namespace:PixelShaderSample"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <StackPanel Orientation="Horizontal">

        <!-- Image without PixelShader effect on the left and image with
             custom shader on the right. -->
        <Image Height="200" Width="200" Source="tree_blossoms.jpg" Stretch="Fill"/>
        <Image Height="200" Width="200" Source="tree_blossoms.jpg" Stretch="Fill">
            <Image.Effect>
                <shader:MyPixelInvertedEffect />
            </Image.Effect>
        </Image>
    </StackPanel>
</UserControl>