基于四元数处理炮身的正确旋转?
Handling Proper Rotation of Cannon Body Based on Quaternion?
这个让我很烦。
我正在尝试根据鼠标输入实现 Cannon.Body 的旋转。
用(Cannon)三帧率的例子来演示一下,就知道是什么问题了。
https://codepen.io/Raggar/pen/EggaZP
https://github.com/RaggarDK/Baby/blob/baby/pl.js
当您 运行 代码并通过单击 "click to play" 区域启用指针锁定控件并按住 W 1 秒以使球体进入相机的视野时,您会看到球体通过应用速度根据 WASD 键移动。如果您移动鼠标,四元数将应用于 Body,并计算适当的速度。
现在旋转 180 度,X 轴上的旋转现在以某种方式被否定了。
当鼠标向上移动时,球体向下旋转。
如何解决此类问题?也许我在其他地方做错了什么,这可能会弄乱四元数?
也许我应该提一下,在播放器控制器 (pl.js) 中,我将旋转应用于 sphereBody,而不是偏航和俯仰对象。
相关代码来自pl.js(第49行):
var onMouseMove = function ( event ) {
if ( scope.enabled === false ) return;
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
cannonBody.rotation.y -= movementX * 0.002;
cannonBody.rotation.x -= movementY * 0.002;
cannonBody.rotation.x = Math.max( - PI_2, Math.min( PI_2, cannonBody.rotation.x ) );
//console.log(cannonBody.rotation);
};
和(第 174 行):
euler.x = cannonBody.rotation.x;
euler.y = cannonBody.rotation.y;
euler.order = "XYZ";
quat.setFromEuler(euler);
inputVelocity.applyQuaternion(quat);
cannonBody.quaternion.copy(quat);
velocity.x = inputVelocity.x;
velocity.z = inputVelocity.z;
在 animate() 函数内部,codepen(第 305 行):
testballMesh.position.copy(sphereBody.position);
testballMesh.quaternion.copy(sphereBody.quaternion);
问题在于您为四元数分配角度和从四元数分配角度的方式。四元数x,y,z,w属性不直接兼容角度,需要转换。
这是为 CANNON.Quaternion 设置绕给定轴的角度的方法:
var axis = new CANNON.Vec3(1,0,0);
var angle = Math.PI / 3;
body.quaternion.setFromAxisAngle(axis, angle);
从四元数中提取欧拉角可能不是解决问题第二部分的最佳方法。当用户移动鼠标时,您可以只存储围绕 X 和 Y 轴的旋转:
// Declare variables outside the mouse handler
var angleX=0, angleY=0;
// Inside the handler:
angleY -= movementX * 0.002;
angleX -= movementY * 0.002;
angleX = Math.max( - PI_2, Math.min( PI_2, angleX ) );
然后将旋转作为四元数,分别使用两个四元数(一个用于 X 角度,一个用于 Y),然后将它们合并为一个:
var quatX = new CANNON.Quaternion();
var quatY = new CANNON.Quaternion();
quatX.setFromAxisAngle(new CANNON.Vec3(1,0,0), angleX);
quatY.setFromAxisAngle(new CANNON.Vec3(0,1,0), angleY);
var quaternion = quatY.mult(quatX);
quaternion.normalize();
要将四元数应用于速度矢量:
var rotatedVelocity = quaternion.vmult(inputVelocity);
专业提示:如果可以避免,请不要使用欧拉角。他们通常造成的问题多于解决的问题。
这个让我很烦。 我正在尝试根据鼠标输入实现 Cannon.Body 的旋转。 用(Cannon)三帧率的例子来演示一下,就知道是什么问题了。
https://codepen.io/Raggar/pen/EggaZP https://github.com/RaggarDK/Baby/blob/baby/pl.js
当您 运行 代码并通过单击 "click to play" 区域启用指针锁定控件并按住 W 1 秒以使球体进入相机的视野时,您会看到球体通过应用速度根据 WASD 键移动。如果您移动鼠标,四元数将应用于 Body,并计算适当的速度。 现在旋转 180 度,X 轴上的旋转现在以某种方式被否定了。 当鼠标向上移动时,球体向下旋转。
如何解决此类问题?也许我在其他地方做错了什么,这可能会弄乱四元数?
也许我应该提一下,在播放器控制器 (pl.js) 中,我将旋转应用于 sphereBody,而不是偏航和俯仰对象。
相关代码来自pl.js(第49行):
var onMouseMove = function ( event ) {
if ( scope.enabled === false ) return;
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
cannonBody.rotation.y -= movementX * 0.002;
cannonBody.rotation.x -= movementY * 0.002;
cannonBody.rotation.x = Math.max( - PI_2, Math.min( PI_2, cannonBody.rotation.x ) );
//console.log(cannonBody.rotation);
};
和(第 174 行):
euler.x = cannonBody.rotation.x;
euler.y = cannonBody.rotation.y;
euler.order = "XYZ";
quat.setFromEuler(euler);
inputVelocity.applyQuaternion(quat);
cannonBody.quaternion.copy(quat);
velocity.x = inputVelocity.x;
velocity.z = inputVelocity.z;
在 animate() 函数内部,codepen(第 305 行):
testballMesh.position.copy(sphereBody.position);
testballMesh.quaternion.copy(sphereBody.quaternion);
问题在于您为四元数分配角度和从四元数分配角度的方式。四元数x,y,z,w属性不直接兼容角度,需要转换。
这是为 CANNON.Quaternion 设置绕给定轴的角度的方法:
var axis = new CANNON.Vec3(1,0,0);
var angle = Math.PI / 3;
body.quaternion.setFromAxisAngle(axis, angle);
从四元数中提取欧拉角可能不是解决问题第二部分的最佳方法。当用户移动鼠标时,您可以只存储围绕 X 和 Y 轴的旋转:
// Declare variables outside the mouse handler
var angleX=0, angleY=0;
// Inside the handler:
angleY -= movementX * 0.002;
angleX -= movementY * 0.002;
angleX = Math.max( - PI_2, Math.min( PI_2, angleX ) );
然后将旋转作为四元数,分别使用两个四元数(一个用于 X 角度,一个用于 Y),然后将它们合并为一个:
var quatX = new CANNON.Quaternion();
var quatY = new CANNON.Quaternion();
quatX.setFromAxisAngle(new CANNON.Vec3(1,0,0), angleX);
quatY.setFromAxisAngle(new CANNON.Vec3(0,1,0), angleY);
var quaternion = quatY.mult(quatX);
quaternion.normalize();
要将四元数应用于速度矢量:
var rotatedVelocity = quaternion.vmult(inputVelocity);
专业提示:如果可以避免,请不要使用欧拉角。他们通常造成的问题多于解决的问题。