围绕一个点旋转会导致 THREE.js 出现奇怪的故障
Rotation around a point causes weird glitches in THREE.js
我场景中的每个元素都由 3 Object3D
的链组成。父子顺序为cellPivot -> modifier -> setup
setup
的目的是通过调整大小/提供一些必须始终存在的填充来永久对齐加载的对象。设置后不应更改
modifier
的目的是真正对对象进行真正的变换
cellPivot
的目的是允许我将 modifier
拖到单元格网格中
为什么需要这一切的一个例子:假设我有一个正交透视的垂直门,我想放在 1x1 space 中,所以我在 x 轴上填充一些以对齐门在中间,类似于下图橙色块是门
因为我想将其移动到地图中的任何单元格,所以我使用 cellPivot
的位置来决定位置。我不能马上使用 modifier
因为有时我想在单元格内旋转模型,这需要同时修改位置和旋转(因为我的模型不是围绕 (0, 0, 0) 构建的,而是沿着 + X 和 +Z)
我通过围绕模型中心(充当枢轴)旋转 modifier
成功地旋转了这些门。下面是执行旋转的函数:
three.Object3D.prototype.pivot = function(pivot, f) {
pivot = lib.VecToVector3(three, pivot); // just a conversion between libs
this.position.sub(pivot);
f(this);
this.position.add(pivot);
return this;
};
three.Object3D.prototype.pivotRotate = function(pivot, axis, theta, rotational = false, abs = false) {
if(abs)
theta -= this.rotation.y; /// not good, handles only y
this.pivot(pivot, () => this.position.applyAxisAngle(axis, theta));
if(rotational)
this.rotateOnAxis(axis, theta);
return this;
};
旋转门工作的线路:
this.o3d.userData.modifier.pivotRotate(this.o3d.userData.center, new three.Vector3(0, 1, 0), this.rot, true);
我现在也在尝试对播放器做类似的事情。我记录按下的键,我计算所需方向的向量的法线(如果我按 W 和 D 我会得到(1, 1),如果我只按 W 我会得到(0, 1)),之后我使用以下行来检测用户想要移动的角度:
Math.atan2(-normal[1], normal[0]);
我已经测试过角度是正确的。最重要的是,“围绕枢轴旋转”之前的代码库使用了相同的代码并且运行良好
每当用户真正想去的方向时,我都会运行以下行:
this.o3d.userData.modifier.pivotRotate(this.o3d.userData.center, new three.Vector3(0, 1, 0), Math.atan2(-normal[1], normal[0]), true, true);
如果用户只是按住一个键,那么 abs
将确保没有进行可见的旋转(因为 theta
将是 0
)
问题来了:每次我按A,不管是不是连着W或者S,角色都会疯狂的旋转。我在上面的行之后添加了以下代码以查看发生了什么:
com.log(new three.Euler().setFromQuaternion(this.o3d.userData.setup.getWorldQuaternion(new three.Quaternion())));
我明白了:
如您所见,x 和 z 正在达到 -pi,而 y 来回摆动。对于不包含密钥 A
的任何其他组合,不会发生这种情况
2天后更新:
我重写了我的函数,如下所示:
我在尝试移动到有问题的位置时在控制台中得到了这些:
正如在第一个日志中看到的那样,我的目标是轮换 0
并打算 -2.35...
,但是 rotAfterRot
显示奇怪的结果..:-pi
和 -.78...
这是 运行 this.rotateOnAxis(axis, theta)
的结果。我已经用 this.rotation.y += theta
更改了这一行。现在一切正常:没有奇怪的 -pi
和 rotAfterRot.y
实际上是 theta
我的猜测是 rotateOnAxis
也在计算对象的其他特征,比如位置,但仍然无法弄清楚它是如何吐出 -pi
我场景中的每个元素都由 3 Object3D
的链组成。父子顺序为cellPivot -> modifier -> setup
setup
的目的是通过调整大小/提供一些必须始终存在的填充来永久对齐加载的对象。设置后不应更改
modifier
的目的是真正对对象进行真正的变换
cellPivot
的目的是允许我将 modifier
拖到单元格网格中
为什么需要这一切的一个例子:假设我有一个正交透视的垂直门,我想放在 1x1 space 中,所以我在 x 轴上填充一些以对齐门在中间,类似于下图橙色块是门
因为我想将其移动到地图中的任何单元格,所以我使用 cellPivot
的位置来决定位置。我不能马上使用 modifier
因为有时我想在单元格内旋转模型,这需要同时修改位置和旋转(因为我的模型不是围绕 (0, 0, 0) 构建的,而是沿着 + X 和 +Z)
我通过围绕模型中心(充当枢轴)旋转 modifier
成功地旋转了这些门。下面是执行旋转的函数:
three.Object3D.prototype.pivot = function(pivot, f) {
pivot = lib.VecToVector3(three, pivot); // just a conversion between libs
this.position.sub(pivot);
f(this);
this.position.add(pivot);
return this;
};
three.Object3D.prototype.pivotRotate = function(pivot, axis, theta, rotational = false, abs = false) {
if(abs)
theta -= this.rotation.y; /// not good, handles only y
this.pivot(pivot, () => this.position.applyAxisAngle(axis, theta));
if(rotational)
this.rotateOnAxis(axis, theta);
return this;
};
旋转门工作的线路:
this.o3d.userData.modifier.pivotRotate(this.o3d.userData.center, new three.Vector3(0, 1, 0), this.rot, true);
我现在也在尝试对播放器做类似的事情。我记录按下的键,我计算所需方向的向量的法线(如果我按 W 和 D 我会得到(1, 1),如果我只按 W 我会得到(0, 1)),之后我使用以下行来检测用户想要移动的角度:
Math.atan2(-normal[1], normal[0]);
我已经测试过角度是正确的。最重要的是,“围绕枢轴旋转”之前的代码库使用了相同的代码并且运行良好
每当用户真正想去的方向时,我都会运行以下行:
this.o3d.userData.modifier.pivotRotate(this.o3d.userData.center, new three.Vector3(0, 1, 0), Math.atan2(-normal[1], normal[0]), true, true);
如果用户只是按住一个键,那么 abs
将确保没有进行可见的旋转(因为 theta
将是 0
)
问题来了:每次我按A,不管是不是连着W或者S,角色都会疯狂的旋转。我在上面的行之后添加了以下代码以查看发生了什么:
com.log(new three.Euler().setFromQuaternion(this.o3d.userData.setup.getWorldQuaternion(new three.Quaternion())));
我明白了:
如您所见,x 和 z 正在达到 -pi,而 y 来回摆动。对于不包含密钥 A
的任何其他组合,不会发生这种情况2天后更新:
我重写了我的函数,如下所示:
我在尝试移动到有问题的位置时在控制台中得到了这些:
正如在第一个日志中看到的那样,我的目标是轮换 0
并打算 -2.35...
,但是 rotAfterRot
显示奇怪的结果..:-pi
和 -.78...
这是 运行 this.rotateOnAxis(axis, theta)
的结果。我已经用 this.rotation.y += theta
更改了这一行。现在一切正常:没有奇怪的 -pi
和 rotAfterRot.y
实际上是 theta
我的猜测是 rotateOnAxis
也在计算对象的其他特征,比如位置,但仍然无法弄清楚它是如何吐出 -pi