3DTools TrackballDecorator实现3D漫游
原文:3DTools TrackballDecorator实现3D漫游
1.基本原理
WPF提供的TrackballDecorator类用来实现三维漫游功能。TrackballDecorator可以看做是在Viewport3D后面的一个虚拟球面,当鼠标点击TraclcballDecorator投影在Viewport3D的这个平面内时,可以在球面上找到与鼠标在平面上面一一对应的一个点。当鼠标运动的时候,照相机根据鼠标的运动来旋转,以此来保证鼠标在这个虚拟球面上的位置是不变的。这样就完成了把把鼠标的二维运动转换为三维运动。下面以一个立方体为模型,简单说明一下上述过程。
图1.1 Viewport3D与TtackballDecorator位置关系
图1.2 鼠标垂直拖动
图1-2表示当鼠标进行垂直移动的时候,球面绕X轴进行旋转,来保证鼠标在球面上的位置是不变的,同时球面内的模型会跟随球面运动,就能得到预期的效果。
2.实现过程
对于每次鼠标移动,都需要计算一个旋转来保证鼠标在球面上的位置是不变的。因此需要做以下两个工作:首先,确定鼠标在球面上的位置;其次,计算鼠标从一个点移动到另一个点所进行的旋转。为了找到鼠标在球体上对应的点,将UIElement坐标系中的二维点投影到的Viewport3D内部的球面上。
(1)首先如何将二维点映射到Viewport3D内部球面呢?下面显示了两个坐标系。
2.1 二维坐标系
2.2 三维坐标系
如图2-1所示,鼠标显示了其在UIElement坐标系中的位置,原点(0,0)位于坐标系的左上角。在图2-2中把鼠标映射到Viewport3D内部的球面上,鼠标的坐标也变换为了三维坐标系中的坐标。
由于最终的目的是得到相机的旋转,因此可以选择最简单的TrackballDecorator球面坐标系,因此可以假定这个球面半径为1,其圆心为坐标系的原点(0,0,0)。只需要构建一个[0,0]—[2,2]的Viewport3D,然后将原点从左上角移动至中心,这样 ViewportsD 就变成了从[-1,1]一[1,-1]。如图 2-3,图 2-4 所示。
2.3 建一个宽、高为2的Viewport3D
2.4 将原点平移至中心
假设鼠标在UIElement坐标系的坐标为(Px, Py),在TrackballDecorator坐标系中的坐标为(x,y, z)那么可得出x,y点坐标如式2-1,2-2所示。
根据球面半径,就能得到Z坐标如式2-3所示。
获取三维坐标信息代码:
private Vector3D ProjectToTrackball(double width, double height. Point point)
{
double X = point.X / (width / 2);
double y = point. Y / (height / 2);
X = X - 1;
y = 1 - y;
double z2=l-x*x-y*y;
double z = z2 > 0 ? Math.Sqrt(z2): 0;
return new Vector3D(x, y, z);
}
这样就得到了鼠标在球面上的坐标(x,y,z)对于鼠标的每次拖动,都需要构建一个旋转,使得鼠标在球面上的位置保持不变。因此需要记录鼠标拖动之前的坐标,和鼠标拖动到当前位置的旋转。为了得到这个旋转需要计算旋转轴和旋转角度。
2.3用向量来描述鼠标的拖动
如图2.3所示向量VI和向量V2分别为原点到鼠标拖动前所在位置和拖动后所在位置的向量。可以简单计算得到旋转轴Axis和旋转角度0,如式2-4、2-5所示。
//根据右手定则,两向量叉乘,确定垂直两向量的轴,即旋转轴
Θ为球面的旋转角度,取Θ的相反数就得到了照相机的旋转角度,当有了旋转轴和旋转角度就可以控制的照相机去进行旋转。
//响应漫游
private void Track(Point currentPosition)
{
Vector3D currentPosition3D =ProjectToTrackball(
EventSource.Actual Width,EventSource.ActualHeight,
currentPosition);
Vector3D axis =Vector3D.CrossProduct(_previousPosition3D,
currentPosition3D);
double angle =Vector3D.AngleBetween(_previousPosition3D,
currentPosition3D);
Quaternion delta = new Quaternion(axis, -angle);
AxisAngleRotation3D r = _rotation;
Quaternion q = new Quatemion(_rotation.Axis, _rotation.Angle);
q*= delta;
_rotation.Axis = q.Axis;
_rotation.Angle = q.Angle;
_previousPosition3 D = currentPosition3D;
}
3.源代码
点击打开链接
3DTools TrackballDecorator实现3D漫游的更多相关文章
- OpenGL实现3D漫游的理解
这篇文章主要参考以下两篇博客: 推导相机变换矩阵 OpenGL系列教程之五:OpenGL矩阵类 上面的第一篇是理论的讲解,第二篇有实例代码,我在后面会给出自己写的主函数,依赖的类可以从第二篇参考中下载 ...
- 3D漫游的分类 3D Navigation Taxonomy
在2001年CHI发表的论文中1,Tan等人提出了一种对3D漫游的分类方法. 当时关于3D漫游(3D Navigation)的研究主要分为两种:一种是发掘有关漫游的认知原则,一种是开发一些具体的漫游技 ...
- 基于 H5 和 webGL 的 3d 智慧城市
前言 中共中央.国务院在今年12月印发了<长江三角洲区域一体化发展规划纲要>(下文简称<纲要>),并发出通知,要求各地区各部门结合实际认真贯彻落实. <纲要>强调, ...
- 轩辕展览-VR虚拟展厅设计如何实现全景漫游功能
什么是在线3d漫游?如何在VR虚拟展厅设计之中实现3d漫游功能?让我们来分享3dVR虚拟展厅的在线漫游. 实际上,在线3d漫游就是通过3d仿真场景,使用鼠标和键盘在虚拟空间之中自由漫游,它可以从高空俯 ...
- 软工1816 · 作业(十二)Beta答辩总结
组长博客 宣传视频 github团队项目仓库 本组成员 队员姓名与学号 124 王彬(组长) 206 赵畅 215 胡展瑞 320 李恒达 131 佘岳昕 431 王源 206 陈文垚 209 陈志炜 ...
- 软工1816 · Beta冲刺(6/7)
团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 推进Web端完成开发 推进修改一些后端接口的逻辑 着手制作视频 接下来的计划 ...
- 软工1816 · Beta冲刺(5/7)
团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 推进后端完成安卓端接口的开发 在测试中发现返回地图接口存在错误(待修复) 推进 ...
- 软工1816 · Beta冲刺(4/7)
团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 推进安卓端各个接口的开发,安卓端各个接口已经基本完成 完成食堂各个平面图的绘制 ...
- 软工1816 · Beta冲刺(3/7)
团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 协助后端完成历史记录接口.美食排行榜接口 完成食堂平面图的绘制 确定web端业 ...
随机推荐
- UVALive - 4960 Sensor network(生成树+LCA)
题目大意:给出N个点.M条边.问这N个点形成的生成树的最大权值边-最小权值边的最小值 解题思路:先排序,然后按生成树的kruscal算法进行加边,再维护一个最小权值边 加边的时候要考虑一下加下去的边是 ...
- 运行一个Hadoop Job所需要指定的属性 分类: A1_HADOOP 2015-02-02 21:33 231人阅读 评论(0) 收藏
1.设置job的基础属性 Job job = new Job(); job.setJarByClass(***.class); job.setJobName("job name") ...
- 如何在电脑上播放iso映像文件
http://blog.sina.com.cn/s/blog_4a20485e0102e5ya.html
- (九)RabbitMQ消息队列-通过Headers模式分发消息
原文:(九)RabbitMQ消息队列-通过Headers模式分发消息 Headers类型的exchange使用的比较少,以至于官方文档貌似都没提到,它是忽略routingKey的一种路由方式.是使用H ...
- 二次封装CoreData
(1)创建一个Data Model文件.命名为MyModel.xcdatamodeld (2)创建Users表,加入如图的字段 (3)创建NSManagedObject subclass表实体文件 ( ...
- 【solr专题之三】Solr常见异常 分类: H4_SOLR/LUCENCE 2014-07-19 10:30 3223人阅读 评论(0) 收藏
1.RemoteSolrException: Expected mime type application/octet-stream but got text/html 现象: SLF4J: Fail ...
- html5 video标签如何禁止视频下载
html5 video标签如何禁止视频下载 一.总结 一句话总结:bing方法给video对象绑定return false的匿名方法. 1.html5 video标签如何禁止视频下载? bing方法给 ...
- 安装alien,DEB与RPM互换
http://blog.csdn.net/sidely/article/details/40181653
- 百度UEditor上传图片-再再总结一次
本周,CSDN有个网友遇到了百度UEditor上传问题,最后商定付50元钱,我帮他解决这个问题. 他最初想自己搞定这个问题,结果搞了好多次,好几天,还是没能解决. 2015年1月17日8: ...
- 【BZOJ 1012】 [JSOI2008]最大数maxnumber(单调队列做法)
[题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1012 [题意] [题解] 后加入的元素,如果比之前的元素大, 那么之前的元素比它小的元 ...