Using Effects in WPF (Part 2)

My previous post on Effects (part of this series) gives a simple example of instantiating an parameterless Effect (it just takes the complement of a color) through XAML. Here we discuss more about the use of Effects.

First, lest you think that Effects are somehow a XAML-only feature, let’s write some code to use Effects. Recall that the invocation of the Effect through XAML looked like this:

 

 

   <Grid >
    <Grid.Effect>
        <eff:ColorComplementEffect />
    </Grid.Effect>

    <Image ...  />
    <Button ... />
    <TextBox ... />
  </Grid>

In code, presuming I already have the Grid and it’s called “myGrid”, we’d just do the following:

 myGrid.Effect = new MyEffects.ColorComplementEffect();

Like everything else in WPF, Effects are readily creatable and manipulable through code. Given that, most of the below will focus on usage through XAML just because it’s the most succinct way of expressing the usage.

The ColorComplementEffect is very limited in what it can do, as it takes no parameters. Let’s look at using an Effect that does take parameters. This is an intensity-thresholding effect – for each pixel, it determines if the pixel is above a certain intensity and, if it is, outputs that pixel. Otherwise it outputs a constant color (transparent by default). The XAML below applies the ThresholdEffect with a threshold value of 0.2, and yellow as the color to fill in those pixels that are below an average 0.2 intensity.

 

 

 

   <Grid >
    <Grid.Effect>
        <eff:ThresholdEffect Threshold="0.25" BlankColor="Orange" />
    </Grid.Effect>
     <Image ...  />
    <Button ... />
    <TextBox ... />
  </Grid>

The result looks like this:

image

Because the ThresholdEffect class exposes Threshold and BlankColor as DependencyProperties, we can use our standard WPF techniques to databind and animate these properties. For instance, the XAML below introduces a slider and wires the Threshold value of the ThresholdEffect to the value of the slider. As you move the slider, more or less of the grid content “thresholds” in and out:

    <Grid >
       <Grid.Effect>
           <eff:ThresholdEffect Threshold="{Binding ElementName=thresholdSlider, Path=Value}" BlankColor="Orange" />
       </Grid.Effect>

       <Image ... />
       <Button ... />
       <TextBox .../>
    </Grid>
    <Slider Name="thresholdSlider" Minimum="0" Maximum="1" ... />
  

Chaining Effects

In the world of GPU programming, there’s a concept known as “multi-pass”, where the programmer sets up multiple pixel shaders and cycles through them, with the output of one becoming the input of the next. In this release of WPF, we do not have explicit support for building multi-pass effects. However, WPF provides a very natural way to express what is typically desired – namely “containment”. Say I want to apply my ThresholdEffect as above, but after that I want to apply the ColorComplementEffect.  A very simple way to do this is to take the Grid shown above, and wrap a Border around it. On this Border, add the ColorComplementEffect. Here’s the XAML:

 <Border>
    <Border.Effect>
        <eff:ColorComplementEffect />
    </Border.Effect>
    <Grid >
        <Grid.Effect>
            <eff:ThresholdEffect Threshold="0.25" BlankColor="Orange" />
        </Grid.Effect>

        <Image ... /> 
        <Button ... />
        <TextBox .../> 
    </Grid>
</Border>

Here’s what this looks like:

image 

Multi-input Effects

The Effects described here receive a single input bitmap from the UIElement that they are attached to, and they can get an arbitrary number of “scalar” properties through DependencyProperties that the Effect author provides for his users, and that they can be chained via element containment. These “scalar” properties are things like double, Color, Point, Point3D, Vector, Vector3D, Size, etc.

One thing that all the Effects thus far have in common is that they have exactly one bitmap input... the rasterization of the UIElement that they're being applied to.  WPF also will support "multi-input" effects where multiple UIElements (or other sources of bitmap data) can be provided to and manipulated by an Effect.  (We don't consider effects like ThresholdEffect to be multi-input even though they have multiple properties/parameters...  we consider "multi-input" to mean receiving more than one bitmap input.)

Multi-input effects will be part of the .NET 3.5 SP1 release, but they're not in the Beta, so we won't discuss them further here.

What have we seen?

Thus far in these posts we’ve looked at invoking GPU-accelerated Effects from your WPF applications and components.

Effects actually do have more features from a “using Effects” point of view, but for now, this is a good stopping point, as what’s been described above represents the bulk of the power and flexibility of Effects. The next post, rather than giving more examples and features, will talk about some of the operational aspects that are important to know about for the stuff described above.