原文:3DTools TrackballDecorator实现3D漫游

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37591671/article/details/68063660

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漫游的更多相关文章

  1. OpenGL实现3D漫游的理解

    这篇文章主要参考以下两篇博客: 推导相机变换矩阵 OpenGL系列教程之五:OpenGL矩阵类 上面的第一篇是理论的讲解,第二篇有实例代码,我在后面会给出自己写的主函数,依赖的类可以从第二篇参考中下载 ...

  2. 3D漫游的分类 3D Navigation Taxonomy

    在2001年CHI发表的论文中1,Tan等人提出了一种对3D漫游的分类方法. 当时关于3D漫游(3D Navigation)的研究主要分为两种:一种是发掘有关漫游的认知原则,一种是开发一些具体的漫游技 ...

  3. 基于 H5 和 webGL 的 3d 智慧城市

    前言 中共中央.国务院在今年12月印发了<长江三角洲区域一体化发展规划纲要>(下文简称<纲要>),并发出通知,要求各地区各部门结合实际认真贯彻落实. <纲要>强调, ...

  4. 轩辕展览-VR虚拟展厅设计如何实现全景漫游功能

    什么是在线3d漫游?如何在VR虚拟展厅设计之中实现3d漫游功能?让我们来分享3dVR虚拟展厅的在线漫游. 实际上,在线3d漫游就是通过3d仿真场景,使用鼠标和键盘在虚拟空间之中自由漫游,它可以从高空俯 ...

  5. 软工1816 · 作业(十二)Beta答辩总结

    组长博客 宣传视频 github团队项目仓库 本组成员 队员姓名与学号 124 王彬(组长) 206 赵畅 215 胡展瑞 320 李恒达 131 佘岳昕 431 王源 206 陈文垚 209 陈志炜 ...

  6. 软工1816 · Beta冲刺(6/7)

    团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 推进Web端完成开发 推进修改一些后端接口的逻辑 着手制作视频 接下来的计划 ...

  7. 软工1816 · Beta冲刺(5/7)

    团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 推进后端完成安卓端接口的开发 在测试中发现返回地图接口存在错误(待修复) 推进 ...

  8. 软工1816 · Beta冲刺(4/7)

    团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 推进安卓端各个接口的开发,安卓端各个接口已经基本完成 完成食堂各个平面图的绘制 ...

  9. 软工1816 · Beta冲刺(3/7)

    团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 协助后端完成历史记录接口.美食排行榜接口 完成食堂平面图的绘制 确定web端业 ...

随机推荐

  1. ios_webView

    iOS开发中WebView的使用 在AppDelegate.m文件里 view sourceprint" class="item about" style="c ...

  2. [React Native] Disable and Ignore Yellow Box Warnings in React Native

    Yellow box warnings in react native can be intrusive. We will use console.disableYellowBox to disabl ...

  3. python3报错

    这个错误是我在从Excel中导入数据,,x,y 和z(z代表了强度)  然后通过xyz画出一个二维的灰度图片所出现的错误 原因是因为用mcml生成的数据如: TypeError: cannot per ...

  4. Vue源码--深入模板渲染

    原文链接:https://geniuspeng.github.io/2018/02/07/vue-compile/ 之前整理了vue的响应式原理,在这里有一点是一直很模糊的,就是何时去new一个wat ...

  5. JDBC之一:JDBC快速入门 分类: B1_JAVA 2014-02-19 14:49 745人阅读 评论(0) 收藏

      (1)下载Oracle的JDBC驱动,一般放在$ORACLE_HOME/jdbc/lib目录,关于驱动的版本请见: http://elf8848.iteye.com/blog/811037     ...

  6. 翻译 | Qt研发副总裁分享2018年工作计划

    原文作者:TuukkaTurunen,高级研发副总裁 翻译校审:Haipeng.Yulong和Ryan 引言:2018年,我们将继续完善Qt 5.9 LTS,现在我们正在为5月份发布Qt 5.11进行 ...

  7. centos7 开启端口防火墙配置(如开启3306或者80端口)

    转载自https://blog.csdn.net/codepen/article/details/52738906 https://www.cnblogs.com/hantianwei/p/57362 ...

  8. SSH连接Linux的Server超时

    SSH连接Linux的Server超时 http://blog.csdn.net/cheng830306/article/details/21796865

  9. [Angular] Subscribing to the valueChanges Observable

    For example we have built a form: form = this.fb.group({ store: this.fb.group({ branch: '', code: '' ...

  10. JS类型转换规则详解

    JS类型转换规则详解 一.总结 一句话总结:JS强制类型转换中的类型名强制类型转换和其它语言不同,是类型类的构造方法,Number(mix) 一句话总结(JS类型本质):因为js是弱类型语言,所以它相 ...