OpenGL鼠标轨迹球(Trackball)原理

OpenGL鼠标轨迹球(Trackball)原理

什么是鼠标轨迹球

类似AutoCAD里的“动态观察”,三维模型都是要投影到二维的屏幕上才能显示给用户,而用户如果想观察一下三维模型的立体形状使用“动态观察”是再好不过了。我们一般的操作是这样的:鼠标(按中健或者其他健)在二维屏幕上拖动,之后三维模型就会以屏幕中心点为中心进行相应的旋转,鼠标拖动得越长,三维模型旋转的角度就越大。AutoCAD这种重量级的商业软件在这方面的用户体验自然是非常完美的了,可你知道它的原理么,如果自己用OpenGL如果实现呢?

OpenGL里的轨迹球

计算机的三维显示类似生活中的摄影,屏幕就是一个相机,三维模型就是被摄物体。我们可以调整相机与被摄物之间的距离来在屏幕显示不同大小影像。轨迹球就是在屏幕之外虚构一个球形曲面,使鼠标在二维屏幕上的移动投影到球形曲面上,这样就能得到更佳的用户体验(不使用轨迹球也能实现动态观察,只是效果很生硬)。

以屏幕为中心为球心,x轴向右,Y轴向上,z轴向屏幕之外,很容易建立一个球体的几何方程如下: $$x^2+y^2+z^2=r^2$$ 这里,r代表球体的半径。

当鼠标在球面的范围内移动时,我们可以由鼠标在二维屏幕上的二维点坐标P(x,y)通过数学关系求得其在球面上的投影点P',鼠标从P1点移动到P2点,对应的在球面上就是从P1'移动到P2'。P1'和P2'与球心之间可以形成两个向量,鼠标移动转化成了向量从V1(OP1'向量)转到V2(OP2'向量),V1和V2的向量叉乘得到向量N即是三维物体的旋转轴,V1到V2的转角量就是三维物体的旋转角度。

使轨迹球更连续

实际的屏幕是个矩形,而球体在平面的投影只会是个圆,因此只要轨迹球的半径不是无限大,就总会有一些区域的点投影后会落在球面之外。此时怎么办呢?

一个好的办法就是在球体投影不能覆盖的区域使用另外一个曲面与之拼接。一个现成的二次曲面能够胜任,它的表达式如下:

$$z(x,y)=\frac{r^2/2}{\sqrt{x^2+y^2}}$$

这个曲面与球面的交线正好一个圆(下图中所示红线),其半径为$r / \sqrt{2}$。

经过这样处理的轨迹球就比较平滑,于是整个坐标计算过程如下: $$z(x,y)=\cases{{\sqrt{r^2-(x^2+y^2)}} & x^2+y^2\leq r^2/2 \\ {\frac{r^2/2}{\sqrt{r^2+y^2}}} & otherwise}$$ $$V_1=\frac{(x_1,y_1,z(x_1,y_1))}{|(x_1,y_1,z(x_1,y_1))|}$$ $$V_2=\frac{(x_2,y_2,z(x_2,y_2))}{|(x_2,y_2,z(x_2,y_2))|}$$ $$N=V_1 \times V_2$$ $$\theta=\arccos V_1 \cdot V_2$$


  1. Object Mouse Trackball

  2. 【OpenGL(SharpGL)】支持任意相机可平移缩放的轨迹球实现