Resumé

Shader Effect con Parametri in Silverlight 3 Beta1

Cristian Merighi () 5,00

Arricchito il Trackball Behavior con un PixelShader (nuovo in Silverlight 3) che modifica l'aspetto dell'UIElement in rotazione in base ad intensità ed incidenza di una luce direzionale virtuale.
Questo articolo è da considerarsi obsoleto. Alcune funzionalità potrebbero non essere più disponibili e non è possibile aggiungere commenti.

Questa pretestuosa prosecuzione del mio ultimo articolo su Silverlight 3 e le sue nuove features ha lo scopo di introdurre e contestualizzare gli shader effects, di sicuro uno strumento di notevole potenza in ottica Ux (User Experience).

Abbiamo visto come "attaccare", utilizzando le librerie di Blend 3, un semplice Trackball behavior ad un UIElement. Ora proviamo - obiettivo del tutorial/articolo - a far mutare l'aspetto dei pixels di tale elemento per ogni atto rotatorio in relazione ad un'ipotetica sorgente luminosa all'interno della scena (demo live cliccando sull'immagine sotto)...

live demo

Cosa fare (step-by-step)?

  • Scrivere un file .fx in codice HLSL(anguage) che contenga la logica necessaria per
    1. ricevere una mappa di pixels come input;
    2. ricevere una coppia di parametri numerici con informazioni riguardo alla luce (incidenza e intensità);
    3. esporre l'algoritmo da utilizzare nel processo di manipolazione per pixel.
  • Compilare il file .fx in un file .ps (pixel shader).
    È necessario il tool fxc(ompiler) presente nel DirectX SDK, e recuperabile dalla cartella «C:\Program Files\Microsoft DirectX SDK (_edition_)\Utilities\bin\x86».
  • Includere il file .ps ottenuto all'interno del progetto Silverlight come risorsa.
  • Wrappare lo shader in una classe che eredita da ShaderEffect e che espone in maniera appropriata gli oggetti da passare allo shader stesso.

In primis quindi: il file .fx:

// 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;
}

Ora la compilazione nel file .ps; si utilizza la seguente riga di comando:

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

Dove /T è il parametro target profile (deve "puntare" a pixel shader 2.0), /E identifica l'entry point (funzione), mentre /Fo specifica il file output.

Successivamente: incapsulare il file .ps nel progetto Silverlight come risorsa.

.ps - resource

Quindi lo shader wrapper, porrò enfasi su pochissime righe di codice (l'intero progetto può essere scaricato dal link presente in fondo all'articolo).

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 */)));

Il markup Xaml aggiornato permette di inserire in maniera dichiarativa le informazioni necessarie sulla luce direzionale:

<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 e codice sono stati implementati con Silverlight 3 Beta1, Non prevedo intendo modificare questo articolo per aggiornarlo alle future versioni di Silverlight.

zip file « Silverlight TrackballBehavior+Shader

Take care. Bye.

Feedbacks

  • Re: Parametric Shader Effect in Silverlight 3 Beta1

    Jose Luis mercoledì 15 luglio 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 venerdì 17 luglio 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

Autore

Cristian Merighi facebook twitter google+ youtube

Ultimi articoli

Top rated

Archivio

Dove sono?

Autore

Cristian Merighi facebook twitter google+ youtube

Le mie letture

Feeds