我正在创建一个基于手机陀螺仪输入旋转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;
答案 0 :(得分:0)
这是我能给你答案的最接近的地方:
首先,您不需要quaternion。 (如果您确实发现自己需要在Euler angles和四元数之间进行转换,只要您按下所有轴惯例,它就是possible。)从设备获得的欧拉角方向信息就足够了代表任何轮换而不含糊不清;如果你正在计算角速度,我同意你要避免欧拉角,因为有一些方向,其中欧拉角的变化率变为无穷大。但你不是,所以你不需要它。
我将尝试总结您尝试解决的潜在问题,然后告诉您为什么它可能无法解决。
您可以通过相机获得设备的完整方向,如偏航,俯仰和滚动。假设偏航就像水平摇摄相机,而俯仰就像垂直倾斜相机一样,那么滚动是一个自由度,不会改变相机指向的方向,但它会影响相机看到的图像的方向。因此,您将获得三个坐标,其中两个与摄像机指向的方向有关,而另一个则没有。
您正尝试将此信息输出到相机控制器,但您只能指定目标位置,即相机正在查看的空间点。这是通过三个笛卡尔坐标来指定的,您可以根据摄像机指向的方向(2个自由度)和到目标对象的距离(一个自由度)来计算。
所以你有三个输入和三个输出,但其中只有两个与彼此有关。 目标位置无法表示摄像机的滚动方向,并且摄像机的方向无法表示到某个目标对象的距离。
由于您没有真正的目标对象,您可以选择任意固定距离(例如1)并使用它。你当然没有任何可以计算它的东西...如果我按照你的代码,你就是根据目标位置来定义距离,目标位置本身是根据与上一步的距离来定义的。这是额外的工作,最好没有任何好处(距离在一些初始值附近漂移),在最坏的情况下数值不稳定(距离漂移到零,你会失去精度或获得无穷大)。只需使用一个固定的距离值,并使其变得简单。
所以现在你可能有一个系统可以将摄像机指向一个方向,但你无法分辨出它的倾斜角度。这意味着你的相机控制器显然只是根据偏航和俯仰角度为你选择它。让我们说它总是选择零度(这将是它可以做的最不疯狂的事情)。当滚动角和偏航角对齐时(当俯仰角为±90°时),这将导致不连续:想象一下,将物理摄像机指向北方地平线并向西偏航,越过西部地平线,并在南部地平线上定居。整个时间,相机的滚动角度是0°,所以没有问题。但是现在想象一下它指向北方的地平线,并且向上俯仰,超过zenith,继续向后俯仰,直到你面向南方地平线。现在相机倒置;滚动角为180°。但是如果摄像机控制器没有将滚动角度从0°改变,那么当你通过天顶时它将会非正常地“翻转”。问题在于,实际上根本没有办法合成基于位置的侧倾角而不会发生这种情况。我们刚刚演示了有两种方法可以将相机从指向北方移动到指向南方,在那里滚动角度最终完全不同。
所以你猜对了。好吧,也许不是。您可以根据设备方向的滚动角度从相机旋转图像吗?也就是说,将回滚添加到显示的图像中?如果是这样,您可能有一个解决方案。假设摄像机控制器的侧倾角始终为零。然后你只需按照所需的滚动角度旋转图像(我猜是从beta
得到的东西?)然后你就完成了。如果摄像机控制器有其他一些选择滚动角度的约定,你需要弄清楚,撤消它,然后重新添加滚动角度。
如果没有我面前的实际系统,我可能无法帮助您调试解决方案。所以我认为这是我在这个问题上的旅程必须结束的地方。祝你好运!
要点: