http://yichuanshen.de/blog/2010/11/13/flipping-elements-with-wpf/

Have you already seen ForgottenTime’s new flip animation eye candy? If not, it’s about time! It took me several days to figure out how to do it…

My first thought was to find out how to do a 4-point-tranformation of a given image. (See figure on the left.) It’s no problem to create an “screenshot” of a UI element and I could easily calculate the four vertices of the transformed image (with given angle and a little bit trigonometry) and transform the original screenshot via the function to achieve a 3D effect. Unfortunately, there’s no (easy and fast) way to do that in C# and Windows Presentation Framework, so I had to think of something else.

After my research on the Internet I came across some official demo WPF applications, also using advanced UI techniques such as flipping. So I dug into the code to find out how they did it. As it turned out, they were using 3D graphics.

WELCOME TO THE 3RD DIMENSION

Strictly speaking a computer screen cannot display real 3D graphics of course, only projections of a 3D space onto a plane… the screen. It’s also called a “viewport”, a 2D window, that allows the user to gaze into the imaginary 3D space behind. Just like we have eyes, a viewport needs a “camera” (to be really precise, a PerspectiveCamera).

Let’s assume the image we want to flip is a square with the dimensions 129×129.

<!-- XAML code -->
<Viewport3D x:Name="viewport3D" Width="129" Height="129">
<Viewport3D.Resources>
</Viewport3D.Resources>
<Viewport3D.Camera>
<PerspectiveCamera x:Name="cam3D"
FieldOfView="45"
LookDirection="0,0,-1 "
UpDirection="0,1,0" />
</Viewport3D.Camera>
</Viewport3D>

After the window is loaded, we create a two-dimensional object, a square, which represents our image in 3D space and calculate where our camera should be. If all that is done, we can literally rotate the object around the y-axis and thus flip the image around.

THE TWO-DIMENSIONAL OBJECT

Every object in our 3D space is made of triangles. The triangle surface of such an object is called a mesh. It’s relatively easy to build a square out of two triangles as the sketch below shows.

We center the image around the origin, so that the camera can be easily positioned on the z-axis. To create such a simple object (notice this is two-dimensional!) you have to write tons of code:

// C# code
GeometryModel3D model3D; private void BuildModel() {
// Customize the brushes
// Can be any brush (ImageBrush, DrawingBrush, VisualBrush, ...)
ImageBrush front = new ImageBrush(this.frontImageSource);
ImageBrush back = new ImageBrush(this.backImageSource);
back.Transform = new ScaleTransform(-1, 1, .5, 0); // Flip back image // Create mesh
MeshGeometry3D mesh = new MeshGeometry3D();
double radius = 129 / 2.0; // 64.5
mesh.Positions.Add(new Point3D(-radius, -radius, 0));
mesh.Positions.Add(new Point3D(radius, -radius, 0));
mesh.Positions.Add(new Point3D(radius, radius, 0));
mesh.Positions.Add(new Point3D(-radius, radius, 0));
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(2);
mesh.TriangleIndices.Add(3);
mesh.TextureCoordinates.Add(new Point(0, 1));
mesh.TextureCoordinates.Add(new Point(1, 1));
mesh.TextureCoordinates.Add(new Point(1, 0));
mesh.TextureCoordinates.Add(new Point(0, 0)); // Add texture
DiffuseMaterial frontMat = new DiffuseMaterial(front);
DiffuseMaterial backMat = new DiffuseMaterial(back);
frontMat.AmbientColor = backMat.AmbientColor = Colors.White; model3D = new GeometryModel3D();
model3D.Geometry = mesh;
model3D.Material = frontMat;
model3D.BackMaterial = backMat; Model3DGroup group = new Model3DGroup();
group.Children.Add(model3D);
group.Children.Add(new AmbientLight(Colors.White)); ModelVisual3D visual = new ModelVisual3D();
visual.Content = group;
viewport3D.Children.Add(visual);
}

THE CAMERA POSITION

The camera has to be some distance away from the square, so that everything is within the camera’s field of view. Especially when the image is rotated by 90˚ around the y-axis, where it’s nearest to the camera. So how do we calculate the distance?

The sketch above shows the image which has already been rotated by 90˚. Let’s first look at the left side of the sketch. As we can see the camera is positioned . We’re going to calculate x using tangent.

Now if we put the camera at  it’s garanteed that everything is visible in the viewport. But as we can see in the sketch above, there’s space below and above (as well as left and right) the original unrotated image (space marked with variable s) which will make the image appear smaller in the viewport. We have to enlarge the viewport, so that the image will appear normal-sized again. We can calculate s as follows:

Now we have made all calculations, we can (finally) transform everything into code:

// C# code
private void PositionCamera() {
double radius = 129 / 2.0; // 64.5 // Calculate 3D cam position for flip animation
double x = radius / Math.Tan(degToRad(45 / 2.0));
cam3D.Position = new Point3D(0, 0, x + radius); // Add border for flip animation
double s = radius * Math.Tan(degToRad(45 / 2.0));
viewport3D.Height = viewport3D.Width = 2 * radius + 2 * s;
} private void Window_Loaded(object sender, RoutedEventArgs e) {
BuildModel();
PositionCamera();
} private double degToRad(double deg) {
return deg / 180 * Math.PI;
}

The degToRad function is needed, because C#’s Trigonometry only takes radian angles.

THE ANIMATION

Now that we have painstakingly set up our beautiful 3D scene, we can finally animate it!

// C# code
public void Flip() {
// Rotate
AxisAngleRotation3D rotation = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0);
model3D.Transform = new RotateTransform3D(rotation, new Point3D(0, 0, 0)); DoubleAnimation flipAnimation = new DoubleAnimation(0, 180, new Duration(TimeSpan.FromMilliseconds(1000)));
/* To flip back just swap 0 and 180 ;) */ // Do magic!
rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, flipAnimation);
}

Try it out! What a glorious effect! Once you saw it, you can’t seem to stop starting the animation over and over again.

Flipping elements with WPF的更多相关文章

  1. WPF 3D 知识点大全以及实例

    引言 现在物联网概念这么火,如果监控的信息能够实时在手机的客服端中以3D形式展示给我们,那种体验大家可以发挥自己的想象. 那生活中我们还有很多地方用到这些,如上图所示的Kinect 在医疗上的应用,当 ...

  2. 30个惊人的插件来扩展 Twitter Bootstrap

    Bootstrap Maxlength It is a lightweight plugin that allows detecting the HTML maxlength property of ...

  3. Github资源汇集

    Github资源汇集 突然发现申请博客园已经两年有余,没有发表过一篇文章,十分惭愧.言归正传,先分享一下两年来收集的部分编程资源,大部分为Github上的项目.虽然网上这样的分享已不在少数,但不如我理 ...

  4. 3D开发基础知识和简单示例

    引言 现在物联网概念这么火,如果监控的信息能够实时在手机的客服端中以3D形式展示给我们,那种体验大家可以发挥自己的想象. 那生活中我们还有很多地方用到这些,如上图所示的Kinect 在医疗上的应用,当 ...

  5. 关于WPF你应该知道的2000件事

    原文 关于WPF你应该知道的2000件事 以下列出了迄今为止为WPF博客所知的2,000件事所创建的所有帖子. 帖子总数= 1,201 动画 #7 - 基于属性的动画 #686 - 使用动画制作图像脉 ...

  6. 2000条你应知的WPF小姿势 基础篇<69-73 WPF Freeze机制和Template>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000ThingsYou Should Know About C# 和 2,00 ...

  7. 2000条你应知的WPF小姿势 基础篇<15-21>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师,对C#和WPF有着极深的热情.最为出色的是他维护了两个博客:2,000Things You Should Know ...

  8. 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇二:基于OneNote难点突破和批量识别

    篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...

  9. WPF下的Richtextbox中实现表格合并,添加删除行列等功能

    .Net中已有现在的方法实现这些功能,不过可能是由于未完善,未把方法公开出来.只能用反射的方法去调用它. 详细信息可以查看.Net Framework 的源代码 http://referencesou ...

随机推荐

  1. jsp_设置错误页

    在各个常用的web站点中,当一个页面出错后,会自动跳转到一个页面上进行错误信息的显示.下面我们说说这个操作是怎么实现的. 要想完成错误页的操作,在jsp页面必须满足两个条件: (1)指定错误出现时的跳 ...

  2. 一些CSS常见的小问题小笔记

    父元素与子元素之间的margin-top问题: 给子元素盒子一个垂直外边距margin-top,父元素盒子也会往下走margin-top的值 解决方法: 1.修改父元素的高度,增加padding-to ...

  3. JS判断手机访问跳转到手机站

    这里提供了六种让手机端访问网站跳转到手机端的方法: 第一种: <script> if(navigator.platform.indexOf('Win32')!=-1){ //pc //wi ...

  4. Xshell_Using X11 forwarding

    FROM:http://www.netsarang.com/tutorial/xshell/1018/Using_X11_forwarding The X11 forwarding feature i ...

  5. elixir 入门笔记

    安装 MAC 平台用 brew 安装 brew update brew install elixir 如果没有 erlang 环境,上面的命令会自定安装 erlang 的环境. 基本数据类型 iex& ...

  6. Xperf Basics: Recording a Trace(转)

    http://randomascii.wordpress.com/2011/08/18/xperf-basics-recording-a-trace/   This post is obsolete ...

  7. [JS] HTML QQ分享界面js代码

    @ - @ :可以自己指定分享内容等....内含JS脚本 <html> <head> <title></title> <script type=& ...

  8. Spring依赖注入(IOC)那些事

    小菜使用Spring有几个月了,但是对于它的内部原理,却是一头雾水,这次借着工作中遇到的一个小问题,来总结一下Spring. Spring依赖注入的思想,就是把对象交由Spring容器管理,使用者只需 ...

  9. Java中的Set, List, Map漫谈

    在编程语言中,集合是指代表一组对象的对象.Java平台专门有一个集合框架(Collections Framework).集合框架是指表示和操作集合的统一架构,隔离了集合的操作和实现细节. 集合框架中的 ...

  10. macd综合版

    参数设置  SHORE 12    LONG 26    MID 9 DIF:EMA(CLOSE,SHORT)-EMA(CLOSE,LONG); DEA:EMA(DIF,MID),COLOR88888 ...