Reflection Pixel Shader Behaviour

I am having so much fun at the moment with my Expression Blend behaviour “verbs” that I decided to look at something that has been interesting me for some time now – Pixel Shader Effects. And in under half a day I have a working example of a reflection pixel shader behaviour. What is more interesting is that I can control the offset of the reflection through the behavour by data binding it to a slider control as shown in the example project.

For background information pixel shaders and the reflection shader in particular please look at the following links:

  1. Greg Schechter’s Blog
  2. Cellbi Software Team’s article on a reflection pixel shader – Create Reflection Shader in Silverlight.

So lets get going with the view of the VS2008 solution.

blog4-1

The complete behaviour code is as follows.

using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Media.Effects;

namespace ReflectionBehaviour
{
    /// <summary>
    /// The <see cref="ReflectionBehaviour"/> class.
    /// </summary>
    public class ReflectionBehaviour : Behavior<UIElement>
    {
        public static readonly DependencyProperty ElementHeightProperty;

        #region Overrides of Behavior

        private readonly ReflectionShader newEffect;
        private Effect oldEffect;

        /// <summary>
        /// Initializes the <see cref="ReflectionBehaviour"/> class.
        /// </summary>
        static ReflectionBehaviour()
        {
            ElementHeightProperty =
                DependencyProperty.Register("ElementHeight",
                                            typeof (double), typeof (ReflectionBehaviour),
                                            new PropertyMetadata(80.0, OnElementHeightChanged));
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ReflectionBehaviour"/> class.
        /// </summary>
        public ReflectionBehaviour()
        {
            newEffect = new ReflectionShader();
        }

        /// <summary>
        /// Gets or sets the height of the element.
        /// </summary>
        /// <value>The height of the element.</value>
        public double ElementHeight
        {
            get { return (double) GetValue(ElementHeightProperty); }
            set { SetValue(ElementHeightProperty, value); }
        }

        /// <summary>
        /// Called when [element height changed].
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnElementHeightChanged(DependencyObject d,
                                                   DependencyPropertyChangedEventArgs e)
        {
            var rs = d as ReflectionBehaviour;
            if (rs != null) rs.OnElementHeightChanged((double) e.OldValue, (double) e.NewValue);
        }

        /// <summary>
        /// Called when [element height changed].
        /// </summary>
        /// <param name="oldValue">The old value.</param>
        /// <param name="newValue">The new value.</param>
        protected virtual void OnElementHeightChanged(double oldValue, double newValue)
        {
            newEffect.PaddingBottomProp = newValue;
        }

        /// <summary>
        /// Called after the behavior is attached to an AssociatedObject.
        /// </summary>
        /// <remarks>
        /// Override this to hook up functionality to the AssociatedObject.
        /// </remarks>
        protected override void OnAttached()
        {
            base.OnAttached();
            oldEffect = AssociatedObject.Effect;
            AssociatedObject.Effect = newEffect;
        }

        /// <summary>
        /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
        /// </summary>
        /// <remarks>
        /// Override this to unhook functionality from the AssociatedObject.
        /// </remarks>
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Effect = oldEffect;
        }

        #endregion
    }
}

Within Expression Blend 3.0 you would use the normal “drag and drop” method to attach the Behaviour.

blog4-2

Configuring the Reflection Pixel Shader Behaviour in Expression Blend is achived through the properties panel as shown below.

blog4-3

The markup within the XAML is as follows:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ReflectionBehaviour;assembly=ReflectionBehaviour"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    x:Class="ReflectionBehaviour.Window1"
    Title="Window1" Height="329" Width="300">
    <Grid>
        <Border BorderBrush="Black" BorderThickness="1" Margin="8,8,8,10">
            <Grid Margin="7">
                <Button Content="Reflection"
                    FontFamily="Impact"
                    FontSize="48"
                    Foreground="#FF0921BD"
                    Background="#FF97ADEA"
                    BorderBrush="Black"
                    Click="Button_Click"
                    VerticalAlignment="Top"
                    Height="86"
                    Opacity="0.5"
                    d:IsEffectDisabled="True">
                    <i:Interaction.Behaviors>
                        <local:ReflectionBehaviour ElementHeight="{Binding Value, ElementName=slider, Mode=Default}"/>
                    </i:Interaction.Behaviors>
                </Button>
                <Slider x:Name="slider"
                    Margin="8,0,8,8"
                    VerticalAlignment="Bottom"
                    Height="28"
                    Maximum="100"
                    SmallChange="1"
                    TickFrequency="10"
                    TickPlacement="Both"
                    Value="85"/>
            </Grid>
        </Border>
    </Grid>
</Window>

In conclusion, the Reflection Pixel Shader Behaviour is a rather smart looking effect as you can see below – a button, a reflection and a slider attached to the reflection offset. The button works as normal and the reflection reflects the mouse-over, click and all other button transitions. Now that is cool…….

blog4-4

Advertisements

~ by Intelligence4 on September 4, 2009.

One Response to “Reflection Pixel Shader Behaviour”

  1. Great article!

Comments are closed.

 
%d bloggers like this: