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. C++函数模版

    如果对于两种不同类型的数值进行比较,可能会写出以下的代码: int compare(const string &v1, const string &v2) { if (v1 < ...

  2. 河南省第六届ACM程序设计大赛

    C:  最舒适的路线 (并查集) #include<cstdio> #include<cstring> #include<iostream> #include< ...

  3. Java方法的封装

    类的封装性即不能让外面的类随意修改一个类的成员变量: 在定义一个类的成员(包括变量和方法),使用private关键字说明这个成员的访问权限,只能被这个类的其他成员方法调用,而不能被其他的类中的方法所调 ...

  4. linux 常用命令大全

    linux 常用命令大全 系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统 ...

  5. linux xwiki搭建过程

    安装mysql数据库,并创建xwiki数据库及用户 mysql> create database xwiki; Query OK, 1 row affected (0.00 sec) mysql ...

  6. line-height,vertical-align及图片居中对齐问题根源解析

    关于图片居中对齐的问题,进入前端行业虽然有一段时间了,以为自己懂了,可是实际上还是一知半解,找了一些博客来看了一下,但是感觉讲的有点碎,看完还是一知半解. 查阅了一下<css权威指南>,结 ...

  7. 安装windows git客户端

    从git官网下载安装包,双击安装,一路默认配置,直到完成 打开git bash,运行 ssh-keygen -t rsa -C "573215750@qq.com" 回车,输入“y ...

  8. Magicodes.WeiChat——多租户的设计与实现

    概要 多租户(Multi Tenancy/Tenant)是一种软件架构,其定义是:在一台服务器上运行单个应用实例,它为多个租户提供服务. 本框架使用的是共享数据库.共享 Schema.共享数据表的数据 ...

  9. 毫无保留开源我写的:IOS Android Ipad 多点触摸通用js 库

    毫无保留开源我写的:IOS Android Ipad 多点触摸通用js 库 在线演示地址: http://m.yunxunmi.com/ 支持 IOS Android Ipad 等不同操作系统的手持或 ...

  10. 【基础知识】.Net基础加强10天

    一. 复习 1. 委托是类型,还是一种引用类型. 2. 使用委托的时候必须new一个委托对象.即便看到代码中没有new委托对象,编译器也会在编译的时候帮我们new赋值给委托的方法,其实是存储在委托对象 ...