Pixel Shaders and Silverlight, WPF

Recently, Silverlight 3 gained the ability to use custom pixel shaders as was already available in WPF. What exactly are custom pixel shaders?

A shader is a set of software instructions executed on your computer’s Graphics Processing Unit (GPU) that performs complex per-pixel effects suh as applying a lighting value, bump mapping (a technique used to make a surface look more realistic by modeling interaction of a bumpy surface texture), shadows, highlights, translucency, and so on.

Pixel shaders are not a part of Silverlight or WPF, but are a technology used with DirectX. You define pixel shaders using a programming language called HLSL (High Level Shader Language), and this definition is stored in a text file with a .fx extension. You can create shaders using NVidia’s Shader Composer Tool (http://developer.nvidia.com/object/fx_composer_home.html)  or other similar tools.

Here is an example of a Negative effect:

sampler2D implicitInput : register(s0);

float4 PS(float2 uv : TEXCOORD) : COLOR
{
float4 color = tex2D(implicitInput, uv);

float4 result;

result.r=1-color.r;
result.g=1-color.g;
result.b=1-color.b;
result.a=color.a;

return result;
}

Note: You can add a text file to your project, give it a .fx extension and then past the above code into it. However, before this code can be compiled properly, you need to change its format to US ASCII. To do this:

– Select the .fx file in the Solution Explorer
– From the Visual Studio File menu, select Advanced Save Options…
– In the Encoding drop down, select US-ASCII

Setting up the Development Environment

Before you can use a pixel shader definition, you must compile the pixel shader .fx source code file into byte code stored in a .ps file. To do this, you need to install the DirectX SDK on  your computer (http://www.microsoft.com/downloads/details.aspx?FamilyID=24a541d6-0486-4453-8641-1eee9e21b282&displaylang=en).

The DirectX SDK has a shader compiler called fxc.exe. By default, it’s stored in the following folder on your computer (the month changes as new versions are released):

C:\Program Files\Microsoft DirectX SDK (November 2008)\Utilities\bin\x86\fxc.exe

 

You need to set up Visual Studio so it knows how to use the fxc.exe tool. To do this:

– In the Visual Studio Tools menu, select External Tools which launches the External Tools dialog.
– Click the Add button, and enter the following information:

Title: Microsoft &Shade Compiler (fxc.exe)
        – Command:  C:\Program Files\Microsoft DirectX SDK (November 2008)\Utilities\bin\x86\fxc.exe
        – Arguments: /DWPF /Od /T ps_2_0 /E $(ItemFileName)PS /Fo$(ProjectDir)$(ItemFileName).ps $(ItemPath)
InstallDirectory:  $TargetDir

– Select the Use Output Window checkbox, then click OK to add the new external tool entry

Now to run the compiler against a .fx file, select the .fx file in the Solution Explorer, then go to the Tools menu and select Microsoft Shader Compiler (fcx.exe). In the Visual Studio Output Window, you should see a “compilation succeeded” message, and the compiler should produce a .ps file with the same stem name as the .fx file. You should include this new file in your project, then set its Build Action property to Resource.

In order to use the new compiled shader effect, you need to create a ShaderEffect class. that loads the pixel shader. First, in your WPF or Silverlight project, you create a subclass of the .NET Framework’s ShaderEffect class.  Here’s an example:

public class SwirlEffect :

ShaderEffect

{

private static PixelShader _pixelShader = new PixelShader()

{

UriSource =

new Uri(“MyVideoProject;component/Swirl.ps”,

UriKind.Relative)

};

public SwirlEffect()

{

PixelShader = _pixelShader;

UpdateShaderValue(InputProperty);

UpdateShaderValue(FactorProperty);

}

public static readonly DependencyProperty InputProperty =

ShaderEffect.RegisterPixelShaderSamplerProperty(“Input”, typeof(SwirlEffect), 0);

public Brush Input

{

get { return (Brush)GetValue(InputProperty); }

set { SetValue(InputProperty, value); }

}

public static readonly DependencyProperty FactorProperty =

DependencyProperty.Register(“Factor”,

typeof(double), typeof(SwirlEffect),

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

public double Factor

{

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

set { SetValue(FactorProperty, value); }

}

Best Regards,
Kevin McNeish
INETA Speaker
Chief Architect, MM .NET Application Framework
www.oakleafsd.com

Leave a Reply

Your email address will not be published. Required fields are marked *