Silverlight 3’s New Pixel Shaders

Silverlight 3 is loaded with new graphical goodies, and one of the goodies I’m most excited about is pixel shaders. A pixel shader is an object that transforms pixels output from the rendering pipeline before they’re rendered to the display surface. Silverlight 3 Beta 1 comes with two pixel shaders: BlurEffect and DropShadowEffect. The following example uses DropShadowEffect to dress up some text:

<TextBlock Text=”Silverlight” Foreground=”Black” FontFamily=”Calibri”

    FontSize=”64″ FontWeight=”Bold”>

    <TextBlock.Effect>

        <DropShadowEffect BlurRadius=”8″ ShadowDepth=”8″ Opacity=”0.5″ />

    </TextBlock.Effect>

</TextBlock>

Here’s the output:

What’s really cool is that you can write custom pixel shaders that can be applied using the same simple, declarative syntax as built-in shaders. Here’s how.

First, if you haven’t already, download and install the latest DirectX SDK. You need the effects compiler (Fxc.exe) from the SDK to compile custom effects.

Next, create an FX file to hold your new effect and implement the effect using Microsoft’s High-Level Shading Language (HLSL). For this example, I wrote the following HLSL in a file named 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);

}

The next step is to compile the FX file into a PS file. To do that, open a DirectX SDK command prompt window and run the effects compiler using a command like this one, which compiles WateryEffect.ps from WateryEffect.fx:

fxc /T ps_2_0 /Fo WateryEffect.ps WateryEffect.fx

As an alternative to running Fxc.exe from the command line, you can download Walt Ritscher’s excellent Shazzam utility and use it to compile PS files. An added bonus with Shazzam is that you can test and debug your effects before compiling them.

Now that your effect has been compiled into a PS file, you need to write a custom Silverlight shader and connect it to the PS file. You do that by deriving a class from System.Windows.Media.Effects.ShaderEffect and providing a default constructor that initializes the PixelShader property with a PixelShader reference. Here’s an example:

public class WateryEffect : ShaderEffect

{

    public WateryEffect()

    {

        this.PixelShader = new PixelShader() { UriSource = new Uri

            (“/CustomShaderDemo;component/WateryEffect.ps”,

            UriKind.Relative) };

    }

}

Be sure to replace “CustomerShaderDemo” with the name of your application assembly. In order for this code to work, you’ll need to add the PS file to your Silverlight project and change its build action to “Resource.” That’s all the constructor code is really doing: creating a PixelShader that’s initialized from a resource named WateryEffect.ps.

Now you’re ready to use your custom shader. First declare an XML namespace prefix that references the namespace (and optionally assembly) in which the WateryEffect class is implemented:

xmlns_custom=”clr-namespace:CustomShaderDemo”

Finally, apply your effect to a XAML object:

<TextBlock Text=”Silverlight” Foreground=”Black” FontFamily=”Calibri”

    FontSize=”64″ FontWeight=”Bold”>

    <TextBlock.Effect>

        <WateryEffect />

    </TextBlock.Effect>

</TextBlock>

To demonstrate, I implemented WateryEffect as described above and applied it to a user control depicting my favorite penguin. Here’s the XAML. Note that two copies of the user control are declared. The one on top has a DropShadowEffect applied to it, while the one on bottom has a WateryEffect applied to it:

<UserControl x_Class=”CustomShaderDemo.MainPage”

    

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”

    xmlns:custom=”clr-namespace:CustomShaderDemo”>

    <Grid x_Name=”LayoutRoot” Background=”White”>

        <StackPanel Orientation=”Vertical” VerticalAlignment=”Center”>

            <custom:Penguin>

                <custom:Penguin.Effect>

                    <DropShadowEffect ShadowDepth=”20″ BlurRadius=”20″ Opacity=”0.4″ />

                </custom:Penguin.Effect>

            </custom:Penguin>

            <custom:Penguin>

                <custom:Penguin.Effect>

                    <custom:WateryEffect />

                </custom:Penguin.Effect>

                <custom:Penguin.RenderTransform>

                    <TransformGroup>

                        <TranslateTransform Y=”-322″ />

                        <ScaleTransform ScaleY=”-1″ />

                    </TransformGroup>

                </custom:Penguin.RenderTransform>

            </custom:Penguin>

        </StackPanel>

    </Grid>

</UserControl>

And here is the result:

 

I based my HLSL code on a sample I found in an excellent blog post by Tamir Khason. HLSL examples abound on the Internet, and the fact that Silverlight 3 supports HLSL opens up a whole new world of possibilities for Silverlight developers.

Jeff Prosise

View Comments

Recent Posts

8-Step AWS to Microsoft Azure Migration Strategy

Microsoft Azure and Amazon Web Services (AWS) are two of the most popular cloud platforms.…

2 days ago

How to Navigate Azure Governance

 Cloud management is difficult to do manually, especially if you work with multiple cloud…

1 week ago

Why Azure’s Scalability is Your Key to Business Growth & Efficiency

Azure’s scalable infrastructure is often cited as one of the primary reasons why it's the…

3 weeks ago

Unlocking the Power of AI in your Software Development Life Cycle (SDLC)

https://www.youtube.com/watch?v=wDzCN0d8SeA Watch our "Unlocking the Power of AI in your Software Development Life Cycle (SDLC)"…

1 month ago

The Role of FinOps in Accelerating Business Innovation

FinOps is a strategic approach to managing cloud costs. It combines financial management best practices…

1 month ago

Azure Kubernetes Security Best Practices

Using Kubernetes with Azure combines the power of Kubernetes container orchestration and the cloud capabilities…

2 months ago