(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Book Folding effect using Pixel Shader

(84 votes)
Miroslav Miroslavov
>
Miroslav Miroslavov
Joined Nov 24, 2009
Articles:   8
Comments:   6
More Articles
3 comments   /   posted on May 25, 2010
Tags:   completit , pixel-shader , book-folding , hlsl , animations , miroslav-miroslavov
Categories:   White Papers , General

This article is compatible with the latest version of Silverlight.

This is part 6 of the series “Silverlight in Action”.

Here we’re sharing our experience from the amazing CompletIT web site.

Introduction

In this article, we’ll examine one very interesting approach for creating Rich UI. It’s a program that manipulates the UI just before the actual rendering on the screen – and it’s called PixelShader. Its name says that this program is processing the Pixels (of a frame that Silverlight renders), and Shader stands for a program that calculates the rendering effect, most of the time - on the GPU.

Pixel shaders in brief:
  1. Pixel shaders are written in HLSL (High Level Shader Language) and are usually saved in “.fx” files.
  2. The code is compiled using DirectFX compiler into “.ps” file.
  3. In Silverlight, the compiled effect is wired by inheriting the ShaderEffect base class.
  4. After that you can apply this effect on UIElements, using the UIElement.Effect property.
  5. At runtime, the effect is executed on each pixel, rendered for that Element(bitmap) and we end up with a new bitmap that is visualized on the screen.

Writing pixel shader effects is very tricky. The HLSL is not very common language and somehow it might be confusing. In order to feel more comfortable during reading this article, we recommend that you to take a look at this article – it’s about shader basics and contains stuff that you’ll need to know in order to create custom pixel shaders.

And let’s see how to create a “Book folding Pixel Shader effect” like this one:

A snapshot of folding the page content

Folding

Try the folding by yourself. Just click on the Image. Get Microsoft Silverlight

Implementation

The ExampleFolding.fx

Pixel shaders can define global input variables by using the so called registers (There is one parameter that is compulsory - sampler2D input  - this is the input bitmap). In our example, we’ll need one more parameter (left) that will be the left position of the element after folding, relative to the original element position. It’ll vary from 0 to 0.5. This can also be the folding angle, but for the sake of simplicity, we’ll use left as an input parameter. At the end, when we run the actual animation on this parameter from 0 to 0.5 and back to 0, we’ll have a folding effect.

Having the left parameter, we’ll use a simple math to transform the current point passed to the main function of the shader (uv). Once we have transformed the point, we’ll get the pixel for that point from the original bitmap – the input parameter.

The transformation of the current point is done by, first, transforming the bitmap bounds to fit in the new bounds (having smaller width) and, second, by interpolating the point, considering the angle of folding.

 sampler2D input : register(s0);
   
 float left : register(c0);
  
 float4 transform(float2 uv : TEXCOORD) : COLOR
 {
     float right = 1 - left;
     float2 tuv = float2((uv.x - left) / (right - left), uv.y); // transforming the curent point (uv) according to the new boundaries.
     
     float tx = tuv.x;
     if (tx > 0.5)
     {
         tx = 1 - tx;
     }
     float top = left * tx;
     float bottom = 1 - top;        
     if (uv.y >= top && uv.y <= bottom)
     {
         float ty = lerp(0, 1, (tuv.y - top) / (bottom - top)); //linear interpolation between 0 and 1 considering the angle of folding. 
         return tex2D(input, float2(tuv.x, ty)); // get the pixel from the transformed x and interpolated y.
     }
     return 0;
 }
   
 float4 main(float2 uv : TEXCOORD) : COLOR 
 {         
     float right = 1 - left;
     if(uv.x > left && uv.x < right)
     {
         return transform(uv);
     }
     
     return 0;
 }

Something that might be very interesting is that during folding, we can see behind the element with the applied effect. This is due to the following code:

 float4 main(float2 uv : TEXCOORD) : COLOR 
 {         
    float right = 1 - left;
    if(uv.x > left && uv.x < right)
    {
        return transform(uv);
    }
     
    return 0;
 }

We’re returning 0 for all points outside the new boundaries and 0 means transparent color.

The ExampleFoldingEffect.cs

This is the class that wires the ExampleFolding.ps and the UIElements. It has two Dependency properties for the shader parameters (the input and left).

 using System;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media.Effects;
  
 namespace FoldingEffect
 {
     public class ExampleFoldingEffect : ShaderEffect
    {
         public static readonly DependencyProperty InputProperty = RegisterPixelShaderSamplerProperty("Input", typeof(ExampleFoldingEffect), 0);
         public static readonly DependencyProperty LeftProperty = DependencyProperty.Register("Left", typeof(double), typeof(ExampleFoldingEffect), new PropertyMetadata(0.0, PixelShaderConstantCallback(0)));
         public ExampleFoldingEffect()
         {
             PixelShader pixelShader = new PixelShader
                                         {
                                              UriSource =
                                                  new Uri("/FoldingEffect;component/ExampleFolding.ps", UriKind.Relative)
                                         };
             this.PixelShader = pixelShader;
  
             this.UpdateShaderValue(InputProperty);
             this.UpdateShaderValue(LeftProperty);
         }
         public Brush Input
         {
             get
             {
                 return ((Brush)(this.GetValue(InputProperty)));
             }
             set
             {
                  this.SetValue(InputProperty, value);
             }
         }        
         public double Left
         {
             get
             {
                 return ((double)(this.GetValue(LeftProperty)));
             }
             set
             {
                 this.SetValue(LeftProperty, value);
             }
         }
     }
 }
Applying the Effect

Applying ExampleFoldingEffect is as easy as applying any other effect (like built-in DropShadowEffect).

 <Border BorderBrush="Black"
         BorderThickness="2"
         Margin="10"
         Padding="5">
     <Image Source="Desert.jpg" />
     <Border.Effect>
         <FoldingEffect:ExampleFoldingEffect x:Name="foldingEffect" />
     </Border.Effect>
 </Border>
Animating the Effect

The shader itself is static if applied once. If we apply the effect for example with a value of 0.25, we’ll see the static half-folded image and that’s it. In order to accomplish the result of animated folding, we’ll have to create an animation over that effect and more precisely – over the Left dependency property. In this way, on each frame of the animation, the effect will be applied again with updated Left property, so the image will be more/less folded.

 <Storyboard x:Name="foldAnimation">
     <DoubleAnimationUsingKeyFrames Storyboard.TargetName="foldingEffect"
                                     Storyboard.TargetProperty="Left">
        <EasingDoubleKeyFrame KeyTime="00:00:00.5"
                                 EasingFunction="{StaticResource easeOut}"
                                 Value=".5" />
        <EasingDoubleKeyFrame KeyTime="00:00:01"
                                 EasingFunction="{StaticResource easeIn}"
                                 Value="0" />
     </DoubleAnimationUsingKeyFrames>
 </Storyboard>

Conclusion

Pixel shaders are very powerful Silverlight features that allow us to manipulate UI rendering on a pixel level. Once that you are comfortable with HLSL, you’ll be able to do amazing things with ease. There are also a lot of great examples out there on the web, built for WPF or Silverlight. You can also browse and examine some of them by using the Shazzam tool, which also gives you a very good environment for creating pixel shaders.

Download the code

Stay tuned for more articles from this series coming up next week.


Subscribe

Comments

  • -_-

    RE: Book Folding effect using Pixel Shader


    posted by Ian on May 26, 2010 00:27
    Nice work, a really useful series of articles.
  • -_-

    RE: Book Folding effect using Pixel Shader


    posted by TheDevX on Sep 17, 2010 03:04
    Are there anyway to toggle 2 picture when folding without use codebehind?
  • forgetu

    Re: Book Folding effect using Pixel Shader


    posted by forgetu on Aug 18, 2011 09:27

    Nice.Thanks.

Add Comment

Login to comment:
  *      *       

From this series