将鼠标拖动运动转换为对象的3D旋转的最佳方法

时间:2020-03-06 14:28:44  来源:igfitidea点击:

我有一个3d对象,希望能够在3d中旋转。最简单的方法是将X和Y鼠标的运动直接转换为绕Y和X轴的旋转,但是如果沿两个轴都有一些旋转,则模型的旋转方式将变得非常直观(即,如果将对象绕一个物体翻转180度轴,则我们沿另一轴的运动将反转)。

我可以简单地执行上述方法,但是不必存储要绕两个轴旋转的量,而是可以存储完整的旋转矩阵,并针对每次鼠标拖动沿相同的轴进一步旋转它,但是我担心那样会很快就会遇到精度问题。

解决方案

创建一个累加器矩阵,并使用标识对其进行初始化。

在绘制对象之前,将每一帧应用于模型视图/世界矩阵状态。

鼠标移动后,以一些灵敏度_constant * delta_x构造绕X轴的旋转矩阵。为另一个组件构造另一个绕Y轴的旋转矩阵。将一个乘以另一个,然后乘到累加器上。

当我们移动鼠标时,累加器将发生变化。绘制时,它将按我们期望的方向定向对象。

同样,谈论四元数的人是正确的;这仅在进行小的增量更改时才看起来不错。如果将其快速拖到对角线上,它的旋转将不会达到我们期望的那样。

我们可以通过对旋转矩阵重新进行归一化处理,使3行中的每行再次垂直,从而解决精度损失的问题。或者,我们可以根据有关对象的现有信息来重新生成要修改的旋转矩阵,这消除了重新规格化的需要。

另外,我们也可以使用四元数,它可以替代Euler角来处理旋转。

在早期的时候,我就从这个常见问题中学到了很多东西,该问题解决了Euler's are Evil中的这个问题(尽管适用于其他应用程序)。

围绕对象垂直于当前拖动方向的轴旋转对象可能是最直观的方式,或者随着每次鼠标的移动而逐渐增加,或者相对于拖动开始位置进行旋转。这两个选项提供的用户交互略有不同,每个交互都有其优缺点。

有一种相对简单的方法将表示围绕轴旋转的角度和3d矢量转换为旋转矩阵。

我们说对了,通过增量旋转更新原始旋转矩阵将导致该矩阵不再是纯旋转矩阵。这是因为3x3旋转矩阵的数据量是表示旋转所需的数据量的三倍。

表示旋转的一种更紧凑的方法是使用Euler Angles(欧拉角),该向量具有最小的3值向量。我们可以将当前旋转作为欧拉角矢量,将其转换为矩阵,应用旋转(增量或者其他方式),然后将矩阵转换回欧拉角矢量。最后一步自然会消除矩阵中的任何非旋转分量,因此我们将再次获得用于下一个状态的纯旋转矩阵。

欧拉角在概念上很好,但是进行来回转换需要大量工作。

一个更实际的选择是四元数(也是),它是四个元素向量。这四个元素指定旋转和均匀比例,并且碰巧如果将向量归一化为单位长度,则比例因子为1.0。事实证明,通过以下方法也可以非常轻松地将角轴值转换为四元数值

q.x = sin(0.5*angle) * axis.x;
q.y = sin(0.5*angle) * axis.y;
q.z = sin(0.5*angle) * axis.z;
q.w = cos(0.5*angle);

然后,我们可以采用当前旋转四元数和增量旋转四元数的四元数乘积(仅使用简单的乘法和加法)来获得表示执行两次旋转的新四元数。在那一点上,我们可以标准化长度以确保纯旋转,但是否则可以继续迭代地组合旋转。

当我们想使用传统的图形API将模型以旋转状态显示时,将四元数转换为旋转矩阵非常简单(仅使用乘法和加法)。

在我的计算机图形学课程中,我们得到了以下代码,这些代码使我们不必重新发明轮子。

跟踪球

跟踪球