Windows Phone

# Animations : Animating Perspective Transforms

4/9/2011 5:11:04 PM
The types of transforms you set with RenderTransform are all examples of two-dimensional affine transforms. Affine transforms are very well behaved and just a little dull: Straight lines are always transformed to straight lines, ellipses are always transformed to ellipses, and squares are always transformed to parallelograms. Two lines that are parallel before the transform are still parallel after the transform.

Silverlight 3 introduced a new UIElement property named Projection that allows setting non-affine transforms on graphical objects, text, controls, and media. Non-affine transforms do not preserve parallelism.

The type of non-affine transform allowed in Silverlight 3 is still represented by a matrix multiplication, and it still has restrictions on what it can do. Straight lines are always transformed to straight lines, and a square is always transformed into a simple convex quadrilateral. By “quadrilateral” I mean a four-sided figure (also called a tetragon or quadrangle); by “simple” I mean that the sides don’t intersect except at their vertices; by “convex” I mean that the internal angles at each vertex are less than 180 degrees.

This type of non-affine transform is very useful for creating taper transforms, where opposite sides of a square or rectangle taper somewhat in one direction. Objects appear to be somewhat three dimensional because part of the object seems further away from our eyes—an effect called a perspective projection.

In a sense, the Projection property gives Silverlight a little bit of “pseudo 3D.” It’s not a real 3D system because there’s no way to define objects in 3D space, no concept of cameras, lights, or shading, and—perhaps most crucially—no clipping of objects based on their arrangement in 3D space.

Still, working with the Projection transform requires the programmer to begin thinking about three dimensions and especially about 3D rotation. Fortunately, the developers of Silverlight have made common and simple use of the Projection property fairly easy.

You can set this Projection property to one of two objects: You can be mathematical and flexible by using Matrix3DProjection, or you can do as I’ll do here and take the easy way out with PlaneProjection. Although PlaneProjection defines twelve settable properties, you can pretty much limit yourself to six of them.

The three crucial properties of PlaneProjection are RotationX, RotationY, and RotationX, which you can set to angle values to cause rotation around the X axis (which extends in a positive direction from left to right), the Y axis (which extends from top to bottom), and the Z axis (which comes out of the screen towards the viewer).

You can anticipate the direction of rotation using the right-hand rule: Point your thumb in the direction of the positive axis. (For X, that’s to the right, for Y it’s down, for Z, it’s toward you.) The curve that your other fingers make indicates the direction of rotation for positive rotation angles. Negative angles rotate in the opposite direction.

A composite rotation depends on the order in which the individual rotations are applied. When you use PlaneProjection, you are sacrificing some flexibility in these rotations. PlaneProjection always applies RotationX first, then RotationY, and finally RotationZ, but in many cases you only need set one of these properties. As with RenderTransform, Projection doesn’t affect layout. The layout system always sees an untransformed and unprojected element.

RotationX, RotationY, and RotationZ are all backed by dependency properties, so they can all be animation targets, as demonstrated by the PerspectiveRotation program. The content area contains a TextBlock with a PlaneProjection object set to its Projection property, and three buttons:

##### Example 1. Silverlight Project: PerspectiveRotation File: MainPage.xaml (excerpt)
 `

Three storyboards defined in the Resources collection are defined to animate the RotationX, RotationY, and RotationZ properties of the PlaneProjection object:

##### Example 2. Silverlight Project: PerspectiveRotation File: MainPage.xaml (excerpt)
 ` `

The buttons simply start the corresponding storyboards:

##### Example 3. Silverlight Project: PerspectiveRotation File: MainPage.xaml.cs (excerpt)
 `void RotateXClick(object sender, RoutedEventArgs args){ rotateX.Begin();}void RotateYClick(object sender, RoutedEventArgs args){ rotateY.Begin();}void RotateZClick(object sender, RoutedEventArgs args){ rotateZ.Begin();}`

Here’s rotation around the Y axis:

The animations are slow enough that you can click multiple buttons and see the interactions. It almost looks as if the text is tumbling through the weightlessness of space.

In 2D space, rotation is relative to a point; in 3D space, rotation is relative to a line, commonly referred to as an “axis of rotation.” But the PlaneProjection class prefers to treat this center of rotation using three numbers—the properties CenterOfRotationX, CenterOfRotationY, and CenterOfRotationZ. In effect, these three numbers define a 3D point that remains unchanged during rotation. CenterOfRotationX does not affect rotation around the X axis, and similarly for the other two properties.

The CenterOfRotationX and CenterOfRotationY properties are relative coordinates based on the size of the element being rotated, where (0, 0) is the upper-left corner. The default values are 0.5, indicating the center of the element.

If you set CenterOfRotationX to 0, the RotationY property causes the element to rotate around its left side. If CenterOfRotationY is set to 1, then the RotationX property causes the element to be rotated around its bottom.

The CenterOfRotationZ property is in absolute coordinates—pixels, in other words—where 0 is the plane of the screen and positive coordinates come out of the screen toward the user. For purposes of its internal calculations, the viewer (you) is assumed to be 1000 pixels in front of the screen. In PerspectiveRotation, try setting the CenterOfRotationZ property of PlaneProjection to 200:

`<TextBlock.Projection>    <PlaneProjection x:Name="planeProjection"                     CenterOfRotationZ="200" /></TextBlock.Projection>`

Now try the “Rotate X” and “RotateY” buttons: You’ll see the text sweep around as if it’s leaving the screen (where the Z coordinate is 0) and circling around a Z value of 200, curving in front of the viewer at a Z value of 400. A CenterOfRotationZ value greater than 500 will cause projections to stop working right. The projected object will get a Z value of 1000 and strike the viewer right on the nose.

The other properties of PlaneProjection cause translation in the X, Y, and Z directions: Conceptually, the LocalOffsetX, LocalOffsetY, and LocalOffsetZ properties are applied first, then the element is rotated, then GlobalOffsetX, GlobalOffsetY, and GlobalOffsetZ properties are applied.

Try setting LocalOffsetX or GlobalOffsetX to 200. In either case, the unrotated text is moved to the right by 200 pixels. But GlobalOffsetX is more like the whole screen shifting right. Try setting LocalOffsetX and rotate the text around the Y axis. The actual offset will begin at the right, and shift to the left, and then back to the right.

You can use animated projection transforms for small effects or for big effects. An example of a big effect is to change the way a new page in your program comes into view. The SweepIntoView program has a MainPage.xaml file containing just a little text:

##### Example 4. Silverlight Project: SweepIntoView File: MainPage.xaml (excerpt)
 ` `

The code-behind file uses touch to navigate to Page2.xaml:

##### Example 5. Silverlight Project: SweepIntoView File: MainPage.xaml.cs (excerpt)
 `protected override void OnManipulationStarted(ManipulationStartedEventArgs args){ this.NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative)); args.Complete(); args.Handled = true; base.OnManipulationStarted(args);} `

For some variety (and to see more clearly what’s happening) Page2.xaml colors its content area with an accented background:

##### Example 6. Silverlight Project: SweepIntoView File: Page2.xaml (excerpt)
 ` `

The code-behind file also has an OnManipulationStarted override:

##### Example 7. Silverlight Project: SweepIntoView File: Page2.xaml.cs (excerpt)
 `protected override void OnManipulationStarted(ManipulationStartedEventArgs args){ this.NavigationService.GoBack(); args.Complete(); args.Handled = true; base.OnManipulationStarted(args);} `

But what makes this program different is some additional markup in the Page2.xaml file. This ensures that the page just doesn’t come on the stage in a sudden pop, but dramatically sweeps into view:

##### Example 8. Silverlight Project: SweepIntoView File: Page2.xaml (excerpt)
 ` `

The PlaneProjection is set to the Projection property of the whole PhoneApplicationPage element, and the animation is triggered when the page is first loaded. The animation makes the RotationY property go from –90 degrees to zero, with a CenterOfRotationX equal to zero. This causes the page to sweep in almost like a door:

Other -----------------