在 javascript 中使用 DeviceOrientation 事件时解决万向节锁定的最简单方法 - 如何制作完美的水平仪/气泡水平仪应用程序

The*_*ist 28 javascript device-orientation deviceorientationevent

从...开始...

\n
window.addEventListener("deviceorientation", handleDeviceTilt);\nfunction handleDeviceTilt(event){\n// Here we can use event.beta, event.gamma\n// Note that we don\'t need event.alpha because that\'s just the compass as we\n// don\'t need to know which way is north to build a simple bubble-level app\n// or similar apps.\n}\n
Run Code Online (Sandbox Code Playgroud)\n

...在这种情况下,只要手机或平板电脑与地面平行(就像放在桌子上),值就很好并且可用betagamma但是,当手机或平板电脑与墙壁平行时,我们无法获得实际值。gamma当设备直立/垂直(即纵向模式)(这是持有移动设备的最常见方式)时,会变得尤其疯狂。

\n
请通过查看此处的立方体来观察 Android 设备的问题
\n

在此输入图像描述

\n

我们需要计算真实的角度,以便我们可以在应用程序中准确地使用倾斜信息。问题是,

\n
\n

为了解锁所谓的 \ngimbal 锁,计算真实角度(例如realBetaand realGamma)(可能通过使用Math.cos()and\n或其他方法)的最简单方法是什么?Math.sin()这可以在没有矩阵和/或四元数的情况下完成吗?我的猜测是“是”,因为伽玛的“扭曲度”在某种程度上与贝塔成正比。如果四元数是唯一的解决方案那么我们到底如何获得realGammaactualGamma使用fixedCorrectGamma它们?

\n
\n

注1:PlayStore上有一个水平仪应用程序,可以完美地显示设备的真实倾斜角度。所以有证据表明这是可行的。然而,截至 2021 年,似乎没有可用的开源代码可用于此类用 javascript 编写的应用程序。

\n

注2:这个问题已经在这里提到过。

\n

注3:精度是必要的。我们越接近精确的角度越好。alpha为简单起见可以省略。

\n

这有什么用?

\n

通过解决这个问题,我们将能够deviceorientation制作类似的东西,\n在此输入图像描述

\n
\n

...或者例如我们可以使用 gamma 在垂直赛车游戏中驾驶汽车。\n在此输入图像描述

\n
\n

您可以通过在移动设备上访问此处(或查找类似内容)来观察实际问题。打开显示 [显示方向角度] 的开关并观察 \xce\xb3 ( gamma)beta接近 90 度。另请参阅当您尝试将设备保持在完全直立位置时,Gyro-Cube 会发生什么情况。

\n

最后的想法,

\n
\n

我们可能需要一些神秘的数学魔法。

\n
\n

Dan*_*cci -1

恐怕仅通过deviceorientation事件获取您正在寻找的信息是不可能的,正是因为您自己所说的原因:gimbal lock

有大批数学家在这方面进行研究,我们从他们的研究中可以了解到的结果是,解决万向节锁定问题的唯一解决方案是避免它:当我们开始靠得太近时,我们必须改变我们的方法。

获得该角度的另一种方法(仅当手机几乎垂直时才有效,因此正是我们需要替代方法时)可能是使用devicemotion数据而不是deviceorientation数据。

window.addEventListener("devicemotion", event => {
  const { x } = event.accelerationIncludingGravity;

  const radiantsRes = Math.asin(x / 9.80665);
  const degreesRes = (radiantsRes * 180) / Math.PI;

  console.log(degreesRes.toFixed(2), radiantsRes.toFixed(10))
});
Run Code Online (Sandbox Code Playgroud)