Click here to Skip to main content
Click here to Skip to main content
Go to top

Create Reflection Shader in Silverlight

, 25 May 2009
Rate this:
Please Sign up or sign in to vote.
Sample code on how to create reflection shader using new pixel shader feature of Silverlight 3

Introduction

It is easy to create pixel shaders in Silverlight. It's basically C# like code. Language for creating shaders is called HLSL - High Level Shader Language. HLSL is heavily used inside video games to create cool graphics. Smile | :) At the moment Silverlight doesn't allow you to define vertex shaders, you can do only pixel.

Please read my blog: Cellbi Software Blog.

See how reflection shader works: Silverlight Reflection Shader Effect.

Steps to Create New Pixel Shader

  1. Create new text file with "fx" extension and place your HLSL code there.
  2. Then compile (not with Visual Studio, but with special effect compiler tool available from DirectX SDK - you can download this from Microsoft web site) your "fx" file to get compiled pixel shader. Compiled pixel shader is placed inside binary file with "ps" extension.
  3. Make sure to include this "ps" file into your project and set its compile type to "Resource".
  4. And finally create new "*.cs" file and place C# shader code there.

Fx File

Effect file should contain HLSL instructions in order to compile. If you are new to HLSL, then read HLSL reference here: HLSL Reference should give you information on language syntax, available data types, operators and functions.

Here is how the simplest "fx" file looks like:

sampler2D input : register(s0);

float4 main(float2 uv : TEXCOORD) : COLOR
{
  return tex2D(input, uv);
}

This line: "sampler2D input : register(s0);" defines "input" variable of sampler2D type. This instruction "register(s0)" defines that data for input variable comes from "s0" register. Next main function is defined - it's C like syntax, except for "TEXTCOORD" and "COLOR" - these are HLSL semantics used by effect compiler and GPU. TEXTCOORD means that "uv" parameter contains texture coordinates, which can get values from 0 to 1. Since "uv" variable has float2 data type, it's possible to access it's "u" and "v" components, e.g. "uv.u", "uv.v", or you can use "uv.x", "uv.y". COLOR semantic means that main function returns color data. "text2D" used inside main function's body is HLSL function which returns color data from the given sampler and texture coordinates.

We are going to define Reflect function for our reflection shader. See below:

float4 Reflect(float2 uv : TEXCOORD) : COLOR
{
  float edge = 0.5;
  if (uv.y > edge)
  {
    uv.y = edge - (uv.y - edge);
    return tex2D(input, uv) * uv.y;
  }
  return tex2D(input, uv);
}

The code is really simple, if uv.y > 0.5, we reflect uv coordinate and return color data, otherwise we use original texture coordinate to return color data. So now we just call Reflect function from our main:

float4 main(float2 uv : TEXCOORD) : COLOR
{
  return Reflect(uv);
}

To compile fx code, you need to run the following command line:

fxc /T ps_2_0 /E main /Fo "Reflection.ps" "Reflection.fx"

For more information, see Fxc Tool.

You can define pre build action for your project:

"fxc" /T ps_2_0 /E main /Fo "$(ProjectDir)Reflection.ps" "$(ProjectDir)Reflection.fx"

fxc tool will create "Reflection.ps" binary file - include it in your project and set compile type to resource.

C# Shader File

Create a new C# file, and paste the following code:

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

namespace ReflectionShader
{
  public class ReflectionShader : ShaderEffect
  {
    public ReflectionShader()
    {
      Uri u = new Uri(@"ReflectionShader;component/Reflection.ps", UriKind.Relative);
      PixelShader = new PixelShader() { UriSource = u };
    }

    public static readonly DependencyProperty ElementHeightProperty =
            DependencyProperty.Register("ElementHeight",
            typeof(double), typeof(ReflectionShader),
            new PropertyMetadata(100.0, OnElementHeightChanged));

    static void OnElementHeightChanged(DependencyObject d, 
      DependencyPropertyChangedEventArgs e)
    {
      (d as ReflectionShader).OnElementHeightChanged((double)e.OldValue, 
						(double)e.NewValue);
    }

    protected virtual void OnElementHeightChanged(double oldValue, double newValue)
    {
      PaddingBottom = newValue;
    }

    public double ElementHeight
    {
      get { return (double)base.GetValue(ElementHeightProperty); }
      set { base.SetValue(ElementHeightProperty, value); }
    }
  }
}

Take a look at the code inside the ReflectionShader constructor - it sets PixelShader property inherited from ShaderEffect class. "ReflectionShader;component/Reflection.ps" - this string sets relative URL to our "ps" file. Since reflection shader needs some space below UI element, we use PaddingBottom property inside OnElementHeightChanged method.

Hot to Use Pixel Shader

It's really simple. Here is the XAML code:

<Button x:Name="btnReflected" Width="200" Height="70">
  <TextBlock FontWeight="Bold" FontSize="25" Text="Reflection" />
  <Button.Effect>
    <local:ReflectionShader ElementHeight="70">
    </local:ReflectionShader>
  </Button.Effect>
</Button>

That's all.

History

  • 25th May, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

SteveLi-Cellbi
Web Developer
United States United States
I'm excited about computers and programming, since my school days. I have master's degree in software development and at the moment I'm a software developer at Cellbi Software.

Comments and Discussions

 
Questionwant to rotate mirror image using HLSL PinmemberVikramRathod17-Jul-12 19:48 
GeneralMy vote of 5 PinmemberVikramRathod17-Jul-12 19:45 
GeneralIt seems doesn't work in WPF project Pinmembernanfang17-Dec-09 17:25 
GeneralNice, simple, effective PinmemberBill Seddon1-Jun-09 23:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 25 May 2009
Article Copyright 2009 by SteveLi-Cellbi
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid