Reflection Shader for Silverlight 3

I’ve become enamored with Silverlight behaviors lately because they provide a clean and easy-to-use mechanism for encapsulating complex behavioral logic and applying it to XAML elements. And I’m equally enamored with Silverlight pixel shaders, which allow similar encapsulation of complex visual effects implemented using Microsoft’s High-Level Shader Language, better known as HLSL.

Last spring, I blogged about a technique for creating reflections programmatically using WriteableBitmap. For TechEd Europe week after next, I decided to go one step futher and create a pixel shader that does the same. Called WetFloorEffect, my shader can be applied in XAML the same way built-in shaders such as DropShadowEffect and BlurEffect are applied:

<custom:PenguinUserControl>

  <custom:PenguinUserControl.Effect>

    <custom:WetFloorEffect SourceHeight=”300″ />

  </custom:PenguinUserControl.Effect>

</custom:PenguinUserControl>

SourceHeight is a dependency property that tells the shader how tall the object you’re reflecting is. Generally, you have to play with SourceHeight a little to get the bottom of the object you’re reflecting (in this example, a user control) to line up with the top of the reflection generated by the shader. Here’s the output from this example:

WetFloorEffect with Full Reflection

WetFloorEffect also exposes a dependency property named ReflectionDepth, which determines the depth (height) of the reflection relative to the height of the object being reflected. Valid values range from 0.0 (0%) to 1.0 (100%). The following example produces a reflection that is half the height of the object being reflected:

<custom:PenguinUserControl>

  <custom:PenguinUserControl.Effect>

    <custom:WetFloorEffect SourceHeight=”300″ ReflectionDepth=”0.5″ />

  </custom:PenguinUserControl.Effect>

</custom:PenguinUserControl>

And here’s the output:

WetFloorEffect with Half Reflection

The shader itself is written in HLSL and looks like this:

sampler2D input : register(s0);

float RelativeHeight : register(c0);

 

float4 main(float2 pos : TEXCOORD) : COLOR

{

    if (pos.y > 0.5)

    {

        pos.y = 0.5 – ((pos.y 0.5) / RelativeHeight);

        return tex2D(input, pos) * pos.y;

    }

    return tex2D(input, pos);

}

Once compiled into a PS file, the shader is encapsulated into a Silverlight effect with the following class definition:

public class WetFloorEffect : ShaderEffect

{

    public static readonly DependencyProperty ReflectionDepthProperty =

        DependencyProperty.Register(“ReflectionDepth”,

        typeof(double), typeof(WetFloorEffect),

        new PropertyMetadata(1.0, PixelShaderConstantCallback(0)));

 

    public double ReflectionDepth

    {

        get { return ((double)(GetValue(ReflectionDepthProperty))); }

        set

        {

            if (value <= 0.0)

                value = 0.00001; // Avoid divide-by-zero errors in HLSL

            if (value > 1.0)

                value = 1.0;

            SetValue(ReflectionDepthProperty, value);

        }

    }

 

    public static readonly DependencyProperty SourceHeightProperty =

        DependencyProperty.Register(“SourceHeight”,

        typeof(double), typeof(WetFloorEffect),

        new PropertyMetadata(0.0, OnSourceHeightChanged));

       

    public double SourceHeight

    {

        get { return (double)GetValue(SourceHeightProperty); }

        set

        {

            if (value < 0.0)

                throw new ArgumentOutOfRangeException

                    (“SourceHeight”, “SourceHeight cannot be negative”);

            SetValue(SourceHeightProperty, value);

        }

    }

 

    static void OnSourceHeightChanged(DependencyObject obj,

        DependencyPropertyChangedEventArgs e)

    {

        ((WetFloorEffect)obj).PaddingBottom = (double)e.NewValue;

    }

       

    public WetFloorEffect()

    {

        PixelShader = new PixelShader() { UriSource =

            new Uri(“/CustomShaderDemo;component/WetFloorEffect.ps”,

            UriKind.Relative) };

        UpdateShaderValue(ReflectionDepthProperty);

        UpdateShaderValue(SourceHeightProperty);

    }

}

There’s a lot going on here, but the gist of it is that WetFloorEffect wraps the compiled HLSL code, which is embedded in the generated assembly as a resource. One item of interest is the call to PixelShaderConstantCallback when the ReflectionDepth dependency property is registered; this maps the value of the property to register c0 in the HLSL, which is in turn mapped to the variable named RelativeHeight. Another point of interest is that the value of SourceHeight is written straight through to the shader’s PaddingBottom property, which is inherited from ShaderEffect. This effectively expands the canvas on which the shader can draw downward by the specified number of pixels.

I’ll explain all this and more during my “Cool Graphics, Hot Code” talk at TechEd. And I’ll have lots of other goodies to share, too.

Easily Migrate from AWS to Azure or an Azure Private Cloud

We help customers move from AWS everyday. If you feel the need to have more options or simply want out of AWS, there are some easy ways to do it. We specialize in Azure hybrid deployments with the flexibility to run applications using private or public clouds — and the ability to move between them.

Overcome AWS Lock-In

We help your team quickly and easily migrate existing deployments away from AWS.

Minimize Redevelopment.

Together we can move existing applications and data without recoding.

Stay Fully Operational

We can be counted on to perform migrations without impacting your existing environments.

  • Up to 50 EC2 (Elastic Cloud Compute) instances
  • Up to 50 TB of EBS (Elastic Block Store) storage with single drives smaller than 1,023 GB
  • Up to 5 subnets
  • Up to 5 network security groups and a total of 50 rules per group
  • Maximum of 20 public IPv4 per subscription

Start Your Migration Today

We offer customers the opportunity to identify how best to migrate off of their current AWS environment. We specialize in helping migrate off of AWS and into Azure or hosted Infrastructure as a Service (IaaS) environments. We provide each customer interested in this service with an executive overview detailing the process and budgetary cost comparison for the new environment.

Stay Informed

Sign up for the latest blogs, events, and insights.

We deliver solutions that accelerate the value of Azure.
Ready to experience the full power of Microsoft Azure?

Atmosera is thrilled to announce that we have been named GitHub AI Partner of the Year.

X