从两个组合角度计算四元数

时间:2017-10-19 14:06:09

标签: javascript typescript three.js

我正在创建一个基于手机陀螺仪输入旋转THREE.js相机的脚本。它目前工作得很好,除了每次我在一个象限上旋转我的手机时,相机将转动180度而不是按预期继续。这是我目前使用的代码:

private onDeviceOrientation = ( event ) => {

  if( event.alpha !== null && event.beta !== null && event.gamma !== null ) {

    let rotation = [
      event.beta,
      event.alpha,
      event.gamma
    ],

    this.orientation = new THREE.Vector3(rotation[0], rotation[1], rotation[2]);
    this.viewer.navigation.setTarget(this.calcPosition());
  }
};

private calcPosition = () => {

    const camPosition = this.viewer.navigation.getPosition(),
          radians = Math.PI / 180,
          aAngle = radians * - this.orientation.y,
          bAngle = radians * + this.orientation.z,
          distance = this.calcDistance();

    let medianX = Math.cos(bAngle) * Math.sin(aAngle);
    let medianY = Math.cos(bAngle) * Math.cos(aAngle);

    let nX = camPosition.x + (medianX * distance),
        nY = camPosition.y + (medianY * distance),
        nZ = camPosition.z + Math.sin(bAngle) * distance;
    return new THREE.Vector3(nX, nY, nZ);
};

window.addEventListener('deviceorientation', this.onDeviceOrientation, false);

以后做了一些研究我发现我需要使用Quaternion来阻止进入新象限时的切换。我没有Quaternions的经验,所以我想知道将上面代码中的两个Vector3组合成一个四元数的最佳方法是什么。

[编辑]

我使用这种方法计算距离:

private calcDistance = (): number => {
    const camPosition = this.viewer.navigation.getPosition();
    const curTarget = this.viewer.navigation.getTarget();
    let nX = camPosition.x - curTarget.x,
        nY = camPosition.y - curTarget.y,
        nZ = camPosition.z - curTarget.z;
    return Math.sqrt((nX * nX) + (nY * nY) + (nZ * nZ));from squared averages
};

我在使用陀螺仪时跟随MDN conventions

[编辑#2] 原来我的角度都错了,我设法通过计算最终位置来解决这个问题:

let nX = camPosition.x - (Math.cos(zAngle) * Math.sin(yAngle)) * distance,
    nY = camPosition.y + (Math.cos(zAngle) * Math.cos(yAngle)) * distance,
    nZ = camPosition.z - (Math.cos(xAngle) * Math.sin(zAngle)) * distance;

1 个答案:

答案 0 :(得分:0)

这是我能给你答案的最接近的地方:

首先,您不需要quaternion。 (如果您确实发现自己需要在Euler angles和四元数之间进行转换,只要您按下所有轴惯例,它就是possible。)从设备获得的欧拉角方向信息就足够了代表任何轮换而不含糊不清;如果你正在计算角速度,我同意你要避免欧拉角,因为有一些方向,其中欧拉角的变化率变为无穷大。但你不是,所以你不需要它。

我将尝试总结您尝试解决的潜在问题,然后告诉您为什么它可能无法解决。

您可以通过相机获得设备的完整方向,如偏航,俯仰和滚动。假设偏航就像水平摇摄相机,而俯仰就像垂直倾斜相机一样,那么滚动是一个自由度,不会改变相机指向的方向,但它会影响相机看到的图像的方向。因此,您将获得三个坐标,其中两个与摄像机指向的方向有关,而另一个则没有。

您正尝试将此信息输出到相机控制器,但您只能指定目标位置,即相机正在查看的空间点。这是通过三个笛卡尔坐标来指定的,您可以根据摄像机指向的方向(2个自由度)和到目标对象的距离(一个自由度)来计算。

所以你有三个输入和三个输出,但其中只有两个与彼此有关。 目标位置无法表示摄像机的滚动方向,并且摄像机的方向无法表示到某个目标对象的距离

由于您没有真正的目标对象,您可以选择任意固定距离(例如1)并使用它。你当然没有任何可以计算它的东西...如果我按照你的代码,你就是根据目标位置来定义距离,目标位置本身是根据与上一步的距离来定义的。这是额外的工作,最好没有任何好处(距离在一些初始值附近漂移),在最坏的情况下数值不稳定(距离漂移到零,你会失去精度或获得无穷大)。只需使用一个固定的距离值,并使其变得简单。

所以现在你可能有一个系统可以将摄像机指向一个方向,但你无法分辨出它的倾斜角度。这意味着你的相机控制器显然只是根据偏航和俯仰角度为你选择它。让我们说它总是选择零度(这将是它可以做的最不疯狂的事情)。当滚动角和偏航角对齐时(当俯仰角为±90°时),这将导致不连续:想象一下,将物理摄像机指向北方地平线并向西偏航,越过西部地平线,并在南部地平线上定居。整个时间,相机的滚动角度是0°,所以没有问题。但是现在想象一下它指向北方的地平线,并且向上俯仰,超过zenith,继续向后俯仰,直到你面向南方地平线。现在相机倒置;滚动角为180°。但是如果摄像机控制器没有将滚动角度从0°改变,那么当你通过天顶时它将会非正常地“翻转”。问题在于,实际上根本没有办法合成基于位置的侧倾角而不会发生这种情况。我们刚刚演示了有两种方法可以将相机从指向北方移动到指向南方,在那里滚动角度最终完全不同。

所以你猜对了。好吧,也许不是。您可以根据设备方向的滚动角度从相机旋转图像吗?也就是说,将回滚添加到显示的图像中?如果是这样,您可能有一个解决方案。假设摄像机控制器的侧倾角始终为零。然后你只需按照所需的滚动角度旋转图像(我猜是从beta得到的东西?)然后你就完成了。如果摄像机控制器有其他一些选择滚动角度的约定,你需要弄清楚,撤消它,然后重新添加滚动角度。

如果没有我面前的实际系统,我可能无法帮助您调试解决方案。所以我认为这是我在这个问题上的旅程必须结束的地方。祝你好运!

要点:

  • 您不需要四元数
  • 选择与模拟目标的固定距离
  • 通过在显示图像之前旋转图像来添加滚动角度
  • 祝你好运!