Resumé

Parametric Shader Effect in Silverlight 3 Beta1

Cristian Merighi () 5.00

Sample Trackball Behavior gets enriched by a PixelShader (new in Silverlight 3) that modifies the aspect of the rotating UIElement based on incidence and intensity of a virtual directional light.
This article is obsolete. Some functionalities might not work anymore. Comments are disabled.

This is a pretextuous prosecution of my last article about Silverlight 3 and its new features: I'd like to introduce and contextualize a serious enhancement to the rendering process, I'm talking about shader effects.

We've seen how to use Blend 3 libraries in order to attach a simple Trackball behavior to an UIElement, now I want that - goal - as soon as the element rotates an hypothetical light modifies the look of the element itself (try the demo by clicking on the following image)...

live demo

What I'm gonna (step-by-step)?

  • Write an .fx file using HLSL(anguage) which contains the logic of
    1. accepting a map of pixels as input;
    2. accepting a couple of numeric parameters which carry informations about light incidence;
    3. returning the algorithm used for the per-pixel handling.
  • Compile the .fx file into a .ps (pixel shader) one
    I need a tool that comes with the DirectX SDK, the fxc(ompiler), stored into the «C:\Program Files\Microsoft DirectX SDK (_edition_)\Utilities\bin\x86» folder.
  • Include the .ps file into my Silverlight project as a resource.
  • Wrap the shader in a class that inherits from ShaderEffect and that properly exposes the members that bridge to the pixel shader (.ps) parameters.

So first: the .fx file:

// s0 <- comes from ShaderSampler 0
// this is the pixel area
sampler2D input : register(s0);
// c0 <- comes from ShaderConstant 0
float dotProduct : register(c0);
// c1 <- comes from ShaderConstant 1
float lightIntensity : register(c1);
float4 main(float2 uv : TEXCOORD) : COLOR
{
    // pretextuous algorithm
    // in a C-like syntax (HLSL actually)
    float goal = dotProduct <= 0.0 ? 0.0 : 1.0;
    float adjust = -lightIntensity  * abs(dotProduct);
    // retrieving the pixel @ the x,y coords
    float4 clr = tex2D( input , uv.xy);
    // do the math stuff
    clr.r = clr.r + (goal - clr.r) * adjust;
    clr.g = clr.g + (goal - clr.g) * adjust;
    clr.b = clr.b + (goal - clr.b) * adjust;
    // return result
    return clr;
}

Now compile it into a .ps file using the following cmd line instruction:

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

Where /T is the target profile parameter (must target pixel shader 2.0), /E identifies the entry point function, while /Fo provides the file output.

Next: encapsulate the generated .ps file into the Silverlight project as a resource.

.ps - resource

Now the shader wrapper, I'll just emphasize some line of code (the entire project can be downloaded at the bottom of the page).

public SpecularShader()

{

    this.PixelShader = SpecularShader.pixelShader;

}

 

static SpecularShader()

{

    pixelShader = new PixelShader();

    pixelShader.UriSource = new Uri("RyoushinSamples;component/shaders/specular.ps", UriKind.Relative);

}

 

public static readonly DependencyProperty InputProperty =

    ShaderEffect.RegisterPixelShaderSamplerProperty(

    "Input",

    typeof(SpecularShader),

    0);

 

internal static readonly DependencyProperty LightIntensityProperty =

    DependencyProperty.Register("LightIntensity", typeof(double), typeof(SpecularShader),

    // !do not put default value in the metadata (it will make the whole thing not work!)

    new PropertyMetadata(PixelShaderConstantCallback(1 /* see c1 in .fx */)));

 

private static readonly DependencyProperty DotProductProperty =

    DependencyProperty.Register("DotProduct", typeof(double), typeof(SpecularShader),

    // !do not put default value in the metadata (it will make the whole thing not work!)

    new PropertyMetadata(PixelShaderConstantCallback(0 /* see c0 in .fx */)));

The updated Xaml markup provides declarative information about scene's directional light:

<Image Source="images/sample.jpg" x:Name="img" Width="420" Height="235"

    HorizontalAlignment="Center" VerticalAlignment="Center">

 

    <Image.Projection>

        <PlaneProjection CenterOfRotationX="0.5"

                        CenterOfRotationY="0.5"

                        CenterOfRotationZ="0.5"

                        RotationY="30"/>

    </Image.Projection>

    <i:Interaction.Behaviors>

        <ryoushin:TrackballBehavior x:Name="trackball"

                                   LightIntensity="1"

                                   LightVectorX=".25"

                                   LightVectorY="-1"/>

    </i:Interaction.Behaviors>

</Image>

Nota bene: demo and code have been implemented on top of Silverlight 3 Beta1, I do not tend nor intend to modify the content of this article to match the future releases of the Silverlight plugin.

zip file « Silverlight TrackballBehavior+Shader

Take care. Bye.

Feedbacks

  • Re: Parametric Shader Effect in Silverlight 3 Beta1

    Jose Luis Wednesday, July 15, 2009 5.00

    Hi, Great article :) When you execute it locally, it does not found the pixel Shader at the specified location component/shaders/specular.ps... Any idea why? The other issue I had converting it to SL3 was the change of the interactivity Library, now it is System.Windows.Interactivity and the using clause is now using the using System.Windows.Interactivity; name instead of the old Microsoft.Expression.Interactivity;.. Best, Jose

  • Re: Shader Effect con Parametri in Silverlight 3 Beta1

    Cristian Merighi Friday, July 17, 2009 0.00

    Sure JL, it an issue - undocumented (or at least I didn't find anything about it yet) - about a subtle change in the format of a packaged resource: add a "Slash" before the assembly name ("<b>/</b>RyoushinSamples;component/shaders/specular.ps") Then it will get correctly the resource.

feedback
 

Syndicate

Author

Cristian Merighi facebook twitter google+ youtube

Latest articles

Top rated

Archive

Where am I?

Author

Cristian Merighi facebook twitter google+ youtube

I'm now reading

Feeds