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.