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

Minimize Redevelopment.

Stay Fully Operational

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

Together we can move existing applications and data without recoding.

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

Comprehensive Capabilities

Comprehensive Capabilities

We can migrate specific workloads from AWS environments with the following supported parameters:

  • 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
Management Server
Atmosera configures and runs this element in AWS which acts as a replication proxy.
Replication Agent
Atmosera uses this element to ensure the replicated data is complete and non-corrupted.

The process leverages intellectual property developed by Atmosera and allows for a fast and non disruptive migration. 
Our propose-built proprietary procedures and software applications help ease the migration using the following elements: We can move your environment to a cloud that fits your needs including private, public and hybrid deployments. Together we pick the best destination for your applications and data. You can count on use to perform the work and get you up and running in a new environment quickly.

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.

We deliver solutions that accelerate the value of Azure.

Ready to experience the full power of Microsoft Azure?

Start Today

Blog Home

Stay Connected

Upcoming Events

All Events