PlaneProjection for 3D effects. Part III : carousels

by Administrator 17. August 2009 00:28

Let's make use of PlaneProjection to program other 3D effects : carousels in this post.

First a simple one, to show how easy it is : just a few lines of code !


Project / source code

The images are not included in the xap file as internal ressources, they are loaded from the web server at run time (to do so, the images must be copied in the ClientBin folder, the one that contains the xap file to be published).

We define a playing ground for the carousel :
 <Grid x:Name="ground" Width="400"  />

The code is self-explanatory (just a bit of very basic geometry to put each image at different angle) :
 string[] arImageNames = { "Amsterdam", "London", "Moskow", "Paris", "Pisa", "Roma",
                           "TajMahal", "Venice" };
 Image[] arImages;
 public MainPage()
 {
  InitializeComponent();
  InitializeCarrousel();
 }
 private void InitializeCarrousel()
 { 
  Storyboard stb = new Storyboard();
  int N = arImageNames.Length;       // number of images
  arImages = new Image[N];
  // for each image
  for (int i = 0; i < N; i++)
  {
   // load image first from the server
   arImages[i] = new Image();
   arImages[i].Width = 150; arImages[i].Height = 150;
   arImages[i].Source = new BitmapImage(new Uri(arImageNames[i] + ".jpg", UriKind.Relative));
   // prepare an image for the carousel
   Image img = new Image();
   img.Width = img.Height = 150;
   img.Source = arImages[i].Source;
   img.Stretch = Stretch.Fill;
   // prepare rotation around the Y-axis
   PlaneProjection pp = new PlaneProjection();
   pp.CenterOfRotationZ = -250;  // center behind the screen
   img.Projection = pp;
   // prepare the animation
   DoubleAnimation da = new DoubleAnimation();
   da.From = i * 360 / N;     // each image at different angle
   da.By=360; da.Duration = TimeSpan.FromSeconds(10);
   da.RepeatBehavior = RepeatBehavior.Forever;
   Storyboard.SetTarget(da, pp);
   Storyboard.SetTargetProperty(da, new PropertyPath("RotationY"));
   stb.Children.Add(da);
   
   // add image to the carousel
   ground.Children.Add(img);
  }
  this.Resources.Add("stb", stb);
  stb.Begin();
 }

Let's now create a more sophisticated carousel :


Project / source code

We replaced each image with a stack panel made of :
- a semi-transparent black rectangle,
- an image,
- another semi-transparent black rectangle.

A bit more geometry to compute the width of each semi-transparent rectangle.

To change speed, we handle the MouseMove event in a colored rectangle and change the Duration property of each animation (as many as images to be displayed). To change rotation, we need to stop the animation and restart it.


To end the day, another carousel :


Project / source code

Each city is displayed as a TextBlock inside a border. For each such border, we add 6 containers (again borders). Doing so, the figure looks more as a circle. The trick is to compute the height of each elementary border : we fixed the

height of each display panel, we know how many cities we have. And we know from basic geometry that a circonference is 2*PI*radius...

 

Tags:

PlaneProjection for 3D effects. Part II : flipping

by Administrator 11. August 2009 03:07

Let's make use of PlaneProjection to program 3D effects : flipping effects in this post (more effects to come in next posts).

As usual, let's start with the easiest one. Please, note that all images have a red circle in the upper-left corner : whenever displaying an image and playing with rotations, it's important to be sure the image is correctly displayed and not the inverted one (the "back side" or mirrored image if you prefer) and it's so easy to be confused without a mark.

Project / Source code

The images are not included in the xap file as internal ressources, they are loaded from the web server at run time. To do so, the images must be copied in the ClientBin folder (the one that contains the xap file to be published). To load these images at run-time (here at start-up time) :
 string[] arImageNames={"Amsterdam", "London", "Moskow", "Paris", "Roma" };
 Image[] arImages;
 .....
 public MainPage()
 {
  InitializeComponent();
  arImages = new Image[arImageNames.Length];
  for (int i=0; i<arImageNames.Length; i++)
  {
   arImages[i] = new Image();
   arImages[i].Source = new BitmapImage(new Uri(arImageNames[i]+".jpg", UriKind.Relative));
  }
  .....
 }

The image is declared in xaml as follows (with an initial -90° rotation along the Y-axis to render it initially invisible) :
 <Image x:Name="img" Width="150" Height="150" Stretch="Fill" ..... >
  <Image.Projection>
   <PlaneProjection x:Name="pp" RotationY="-90" />
  </Image.Projection>
 </Image>

We animate the plane projection from -90° to 90° (we will change image at the end of each elementary animation) :
 <Grid.Resources>
  <Storyboard x:Name="stb"  Completed="stb_Completed" >
   <DoubleAnimation x:Name="da" Storyboard.TargetName="pp" Storyboard.TargetProperty="RotationY" Duration="0:0:4" From="-90" To="90"  />

  </Storyboard>
 </Grid.Resources>

The DoubleAnimation line could be written, without giving a name (here pp) to the PlaneProjection :
 <DoubleAnimation x:Name="da" Storyboard.TargetName="img" Storyboard.TargetProperty="(Image.Projection).RotationY" Duration="0:0:4" From="-90" To="90" />

In the function that handles the Completed event (N being the index of the image being displayed) :
 private void stb_Completed(object sender, EventArgs e)
 {
  N = ++N % arImageNames.Length;
  img.Source = arImages[N].Source;
  stb.Begin();
 }
Really, nothing complicated !


And now another way to flip pages :

Project / source code

We use three panels and each panel is made of two images :
- a small image of the spirals (just half of it), inserted as a ressource,
- the displayed image (not always the same, for instance Amsterdam.jpg or the first or the last image), these images being kept on the web server (in the same folder as the xap file).

These three panels (all with CenterOfRotationX equal to 0) are :
- one panel for the left side : fixed, with RotationY of 180° (so, we can see a full spiral from two half-sized images) and image initially invisible,
- one panel for the right side : fixed, with RotationY of 0° and an image (title image) initially present,
- a moving panel, initially invisible (it will become visible when the users clicks the Next or Previous link button).

When the user clicks Next or Previous and the action is valid (they are more images to be displayed), we :
- prepare the moving panel (copy of an image and preparation of the storyboard),
- prepare the left panel (if click on Previous) or the right panel (if click on Next) with a copy of an image that will become more and more visible,
- make the moving panel visible and start the animation.

Whenever we flip page from left-to-right or right-to-left, the animation is performed in two steps : - for a right-to-left-flip (Next action), a first animation from 0° to 85° (we then change image in the moving panel) and then a second animation from 85° to 180° (the moving panel becomes then invisible),
- for a left-to-right flip (Previous action), a first animation from 180° to 85° (with then a change of image in the moving panel) and then a second animation from 85° to 0° (the moving panel becomes then invisible).

More details in the source code file available.
 

Flipping is not restricted to images. We can flip between data forms :

Project / source code

This animation is similar (even easier) to the previous one : we have again three panels. We just added :
- RotationX="-340" and RotationY="-40" to the PlaneProjection of the back panel
- RotationX="-20" and RotationY="-40" to the PlaneProjection of the front panel.

Since we accept to see the back side of data forms during animations, the animations can be performed in only one step (a RotationX from -20° to -340° for Next and -340° to -20° for Previous).

See soon for other effects.

 

Tags:

Silverlight 3 Tools now available for non-ENU versions of development tools

by Administrator 4. August 2009 14:17

Silverlight 3 Tools may now be installed with non English versions of Visual Studio and Visual Web Developer Express. Available languages are : French, German, Italian, Japanese, Korean, Spanish and Chinese' (both simplified and traditional).

Download these tools here

Those using non-ENU versions of development tools can now enjoy Silverlight 3 development.

 

Tags:

PlaneProjection for 3D effects. Part I

by Administrator 31. July 2009 07:20

Silverlight 3 is not fully but somewhat 3D. It means you cannot expect the capabilities of Direct3D (though some libraries from 3rd parties are in progress and promising) but there is enough today in SL3 to easily implement eye-catching 3D effects. In this serie, we will implement a bunch of them.

But first, in this part one, the basis illustrated by two programs you can play with, to experiment. These two programs help you to visualize the rendering of perspective transforms. The first program helps in the understanding of the basic plane transformations while the second allows you to animate projections.

To provide these 3D effects, you just need to implement a plane projection, ie a transformation that gives perspective to a 2D plane surface. For instance (here a PlaneProjection applied to an image but it's applicable to buttons, complex forms, grids, ie anything that has a visual 2D representation) :

 <Image Source=..... >
  <Image.Projection>
   <PlaneProjection ..... >
  </Image.Projection>
 </Image>


PlaneProjection has a few attributes you need to know, each with X, Y and Z variants : first Rotation (thus RotationX, RotationY and RotationZ) to specify rotation angles, then CenterOfRotation (thus CenterOfRotationX, CenterOfRotationY and CenterOfRotationZ) to specify axes of rotation. With just these two attributes (well, six...), you can already perform a lot. To go a bit further, there are LocalOffset and GlobalOffset (again, with the X, Y and Z variants) to specify two types of translation. Let's forget LocalOffset and GlobalOffset for the moment.

Before experimenting, a few words about the axis. The X-axis is horizontal, from left to right. The Y-axis is vertical, from top to bottom. The Z-axis is perpendicular, from inside to outside of the screen. With RotationX, we rotate a surface (for instance an image) around the (horizontal) X-axis. The rotation angle is expressed in degrees. As expected, with RotationY, we rotate the surface around the (vertical) Y-axis. With RotationZ (and with other default values), we rotate the surface around the center point, without leaving 2D space (by default, rotation around the center of the surface). Take time to experiment with the first program to feel at ease.

With CenterOfRotation, we change rotation axis. CenterOfRotationX and CenterOfRotationY are in the 0 to 1 range. CenterOfRotationX has an influence on RotationY while CenterOfRotationY has an influence on RotationX. Both have an influence on RotationZ.

0 in CenterOfRotationX corresponds to the left side of the surface (the one we apply the PlaneProjection) and 1 to the right side. A RotationY operation is then performed around a vertical axis that doesn't anymore traverse the surface center (though this new vertical rotation axis remains parallel to the Y-axis).

0 in CenterOfRotationY corresponds to the top side of the surface and 1 to the bottom side. RotationX is then performed around an horizontal axis that is parallel to the X-axis.

CenterOfRotationZ indicates a distance along the Z-axis. If attribute CenterOfRotationZ has a value of -200 (the point is then behind the screen) and you perform a RotationY operation, a rotation is performed around a vertical axis that traverses the point at -200 along the Z-axis. As the surface (an image or a form in the following program) is rotated, it appears smaller and smaller (the image is moving away) until RotationY reaches the value 180. If rotation continues, the surface appears larger and larger (the image is coming back to you), to its original size when RotationY reaches the value 360.

Let's experiment.

When a surface is rotated, the content disappears (it becomes very thin) and then, the back of the surface becomes visible ! Funny to discover the back side of pixels (as if the surface was drawn on a pane of glass) but unfortunately rarely realistic. This is a problem we will have to solve. Do not expect to solve the problem with a surface made of two consecutive images : the first one will not become the back side of the second one (Silverlight will only take the last one into account).

Now, let's explain LocalOffset and GlobalOffset. Both perform a translation (along the X, Y and Z axis, depending on the variant). GlobalOffset performs a translation along the X, Y and Z axis of the screen. These are fixed and unaffected by Rotation operations. X is always horizontal (from left to right) and Y always vertical (from top to bottom). GlobalOffset is always performed as the last transform, just before painting on the screen.

LocalOffset is performed after the rotation. This rotation (that depends on Rotation attributes) changes axis : if RotationZ is 90 (anti-clockwise rotation with positive values), the X-axis becomes vertical (from bottom to top) ! LocalOffsetX performs then a translation along the newly configured X-axis. GlobalOffsetX would always perform an horizontal translation. If no rotation is specified in the PlaneProjection attributes, LocalOffset and GlobalOffset have the same effect.

Experiment with the following program. Be careful, since some attributes are initialized (for the automatic animation), reset them to reinitialize with default values.

In the following posts, we will make use of these PlaneProjection.

Tags:

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

About the author

Gerard Leblanc is the author of several books (in french) on C++, C#, .NET and Silverlight (Eyrolles, Paris as publisher). See www.gleblanc.eu as the companion web site for these books (included sample programs).
He is Microsoft MVP for Silverlight.

MVP logo