Flipping elements with WPF
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的更多相关文章
- WPF 3D 知识点大全以及实例
引言 现在物联网概念这么火,如果监控的信息能够实时在手机的客服端中以3D形式展示给我们,那种体验大家可以发挥自己的想象. 那生活中我们还有很多地方用到这些,如上图所示的Kinect 在医疗上的应用,当 ...
- 30个惊人的插件来扩展 Twitter Bootstrap
Bootstrap Maxlength It is a lightweight plugin that allows detecting the HTML maxlength property of ...
- Github资源汇集
Github资源汇集 突然发现申请博客园已经两年有余,没有发表过一篇文章,十分惭愧.言归正传,先分享一下两年来收集的部分编程资源,大部分为Github上的项目.虽然网上这样的分享已不在少数,但不如我理 ...
- 3D开发基础知识和简单示例
引言 现在物联网概念这么火,如果监控的信息能够实时在手机的客服端中以3D形式展示给我们,那种体验大家可以发挥自己的想象. 那生活中我们还有很多地方用到这些,如上图所示的Kinect 在医疗上的应用,当 ...
- 关于WPF你应该知道的2000件事
原文 关于WPF你应该知道的2000件事 以下列出了迄今为止为WPF博客所知的2,000件事所创建的所有帖子. 帖子总数= 1,201 动画 #7 - 基于属性的动画 #686 - 使用动画制作图像脉 ...
- 2000条你应知的WPF小姿势 基础篇<69-73 WPF Freeze机制和Template>
在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000ThingsYou Should Know About C# 和 2,00 ...
- 2000条你应知的WPF小姿势 基础篇<15-21>
在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师,对C#和WPF有着极深的热情.最为出色的是他维护了两个博客:2,000Things You Should Know ...
- 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇二:基于OneNote难点突破和批量识别
篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...
- WPF下的Richtextbox中实现表格合并,添加删除行列等功能
.Net中已有现在的方法实现这些功能,不过可能是由于未完善,未把方法公开出来.只能用反射的方法去调用它. 详细信息可以查看.Net Framework 的源代码 http://referencesou ...
随机推荐
- js的变量使用<bean><list:write>赋值时需加' '
script的变量使用<bean><list:write>赋值时需加' ',如:var code ='<bean:write name="target" ...
- c++中关于static关键字的问题
C++的static关键字C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static.前者应用于普通变量和函数,不涉及类:后者主要说明static在类中的作用. ...
- Linux启动ftp服务器530 Permission denied解决方法(已试,行)
Linux启动ftp服务器530 Permission denied解决方法重新在虚拟机下安装了linux.现在我想启动linux自带的ftp服务器:#service vsftpd start . ...
- nginx做反向代理并防盗链
nginx做反向代理真的非常简单,只需设置location+proxy_pass即可. 防盗链配置有些复杂,需要注意的地方: 在防盗链的location中需要再设置一下proxy_pass(在这里走了 ...
- Google 镜像站搜集[转]
Google 镜像站搜集 原文链接:http://www.itechzero.com/google-mirror-sites-collect.html 如果您是以下镜像的作者,并且不希望您的镜像出现在 ...
- 2014年市场需求排名前10的编程语言 - 生命的延续是 BI
开篇介绍 2014年就快收尾了,Team 内部每人都会准备一些 Tech Talk 的内容,技术方面的,咨询方面的都可以.我就准备了一些有关 BI 排名,BI 报表排名,包括各种技术编程语言等相关排名 ...
- 自己动手写UI库——引入ExtJs(布局)
第一: 来看一下最终的效果 第二: 来看一下使用方法: 第三: Component类代码如下所示: public class Component { pub ...
- [WinAPI] API 1 [桌面上画一个简单彩色图形]
#include<Windows.h> void GdiOut(HDC hdc); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hP ...
- Linux内存寻址
我会尽力以最简洁清晰的思路来写这篇文章. 所谓内存寻址也就是从写在指令里的地址,转化为实际物理地址的过程.因为操作系统要兼顾许多东西,所以也就变得复杂. 逻辑地址 → 线性地址 → 物理地址 逻辑地址 ...
- maven nexus 3 third party 构件上传
mvn -e deploy:deploy-file -DgroupId=com.oracle -DartifactId=JDBCDriver -Dversion=12.0.1 -Dpackaging= ...