3D旋转概念以及计算方法
用鼠标旋转相机
实现一个虚拟轨迹球(原代号为Avalon的Windows Presentation Foundation的)
丹尼尔Lehenbauer http://blogs.msdn.com/danlehen
抽象
一般人想要做的显示三维模型后,他们的第一件事是一下就可以用鼠标旋转。通过鼠标旋转三维对象最常见的技术被称为“虚拟轨迹球”。本文将描述一个轨迹球做什么和步行通过实施机制。在结束示例代码的链接,用鼠标在你自己的WPF应用程序,您可以使用旋转相机。
图1a 老虎在其原始配置模型 |
图1b 虎小鼠模型后一直拖到左略有下降。 |
1。介绍
轨迹球转换成三维旋转的2D鼠标的移动。这是通过投影鼠标的位置上,如图2所示的假想球落后的Viewport3D。随着鼠标移动相机(或场景)旋转,以保持对鼠标指针下方领域的相同点。
图2a Viewport3D的立方体,从用户的角度来看,落款轨迹球 |
图2b 侧视图说明映射到鼠标的位置,球体上的点 |
水平移动鼠标时,必须保持一个关于Y轴的旋转相同的点下鼠标指针。
图3 垂直移动鼠标旋转的Y轴的场景 |
同样,垂直变化中的X轴旋转的鼠标位置的结果。
图4 垂直移动鼠标绕X轴旋转场景 |
此接口提供了一个比较直观的方法,其中一个模型可以操纵通过了关于X和Y轴的旋转组合成任何方向。
2。计算旋转
在每个鼠标移动事件中,我们需要计算出一个旋转,以保持相同的点下鼠标指针。这样做有两个步骤。首先是搞清楚什么球体上的点下鼠标指针。二是计算需要改造旧了点的新的起点上旋转。
2.1寻找球点
为了找到球体上的点下鼠标指针,我们需要 刻在Viewport3D的球体投射在二维点的UIElement的坐标系。图5显示了两个坐标系统。
图5a 鼠标报告UIElement的,其中有(0,0)在左上角的坐标空间中的位置。 |
图5b 我们预计在这个二维点刻在Viewport3D的球体。请注意,这个结果在一个三维坐标。 |
由于我们只计算的旋转,我们可以选择两者协调的领域,对我们来说是最方便的系统感兴趣。这是最简单的使用了球形半径 = 1原点(0,0,0)为中心。这使得发现的X和Y分量在两个如图6所示的二维坐标系统之间的转换的工作。
图6a 坐标系统的UIElement |
图6b 协调系统,我们的轨迹球 |
要做到这一点,我们构建了一个规模将映射Viewport3D的界限范围[0,0] - [2,2]。然后,我们应用翻译从左上角移动到中心的起源。这使得我们的观点,在范围[1,1] - [1,-1]。最后,我们占为Y轴朝下,而不是在二维坐标系统。
/ / [0,0]规模界限 - [2,2] 双X = PX /(宽/ 2); 双Y = PY /(身高/ 2);
/ /翻译0,0中心 X = X - 1;
/ /翻转+ Y是,而不是向下 Y = 1 - Y; |
现在,我们已经发现我们的x和y位置上球体,我们可以发现ž。由于我们的球半径 = 1,我们知道。以解决ž我们得到:
双Z2 = 1 - X * X - Y * Y; 双?Z = Z2> 0 数学 SQRT (Z2):0;
的Vector3D p.Normalize(); |
现在,我们有( X , Y , Z 球体上的点)下方的鼠标指针的坐标。
2.2旋转点之间的
在每个鼠标移动,我们要构建一个旋转,将保持对鼠标指针下方领域的相同点。为此,我们从上次鼠标移动事件记忆球体上的点和建设,将改变目前点下鼠标指针旋转。
计算旋转,我们需要两件事情:
- 旋转轴
- 旋转角度θ
图7 我们需要找到轴和旋转角度θ,将改变V 1到V 2。 |
在以原点为中心,因为我们的球,我们可以解释我们的观点,作为载体。它这样做是微不足道的轴和旋转角度分别使用交叉的产品和网点产品:
的Vector3D 轴的Vector3D(V1,V2); 双θ= 的Vector3D,。AngleBetween(V1,V2); |
一旦我们拥有了这一切仍然是当前方向申请新的旋转轴和角度:
/ /我们否定的角度,因为我们正在旋转的摄像头。
/ /不要做,如果你正在旋转的场景代替。
四元三角= 新 四元数(轴角);
/ /获取当前orientantion的RotateTransform3D
RotateTransform3D RT =(RotateTransform3D)camera.Transform ;
AxisAngleRotation3D R =(AxisAngleRotation3D)rt.Rotation的的 ;
四元数Q = 新 四元(r.Axis, r.Angle)
/ /构图方向与以往的三角洲
Q * =三角洲;
/ /写入新的方向返回到Rotation3D
r.Axis = q.Axis ;
r.Angle = q.Angle ;
3。其他细节
也有一些细节,我们在第2掩饰。首先是投射到球体的鼠标指针,计算假设Viewport3D的是方形的。Viewport3D的如果是椭圆形刻轨迹球实际上是一个椭球:
图8 如果Viewport3D的是椭圆形的题写的轨迹球,实际上是一个椭球 |
这种效果是通常不引人注目,但如果长宽比是极端的,这将导致旋转速度沿较短的轴移动时速度明显加快。为了纠正这个问题,你可以申请一个统一的尺度时二维点映射到球体,而不是(宽度, 高度)。例如,分(宽度,高度)会的工作。无论你选择,记得翻译的起源时,此帐户。
另一个问题是如何处理的情况下,当鼠标指针不映射到轨迹球定位:
图9 阴影区域不映射到一个点上的轨迹球 |
一个可行的办法是打击Z在这种情况下为零,然后年底的2.1节所示:
双?Z = Z2> 0 数学 SQRT (Z2):0;
从技术上讲,我们也应该正常化x 和 y 找到轨迹球最近在点Z = 0平面的,否则我们返回的是不球体上的:
然而,在2.2节中,我们使用的Vector3D 。AngleBetween(V1,V2)占 非规范化的载体。这是正常化的产量x 和 y 相同的结果如上图所示。
我们还没有讨论的模型和摄像机的初始位置。此实现假定该模型为中心的起源和相机正在研究的起源和定位在距离该模型是可见的。
最后,本文不讨论如何实现变焦,虽然示例代码包含一个合理的实施。
4。示例代码
示例代码包含三个可重用件:
trackball.cs |
观察一个FrameworkElement的鼠标事件,由此产生的旋转和尺度,以更新的Transform3D 实用程序类。
|
trackport.proj |
一个UserControl的加载和显示XAML从松散。Model3D 允许的观点,通过鼠标(例如使用的操纵Trackball.cs)
|
ModelViewer.proj |
模型查看器应用程序图,在图1(使用例如Trackport.proj的)。 |
这些都包含在“3D工具的Windows Presentation Foundation”在此URL的工作区:http://workspaces.gotdotnet.com/3DTools
下载的版本,其中既包括二进制和源代码(在这里)你不必参加工作区。