根据四元数处理炮台身体的适当旋转?

6
这个问题让我很困扰。 我正在尝试根据鼠标输入实现炮弹身体的旋转。 使用(Cannon)Three FPS示例来演示,您可以看到问题所在。

https://codepen.io/Raggar/pen/EggaZP https://github.com/RaggarDK/Baby/blob/baby/pl.js

当您运行代码并通过单击“单击播放”区域启用pointerlockcontrols,并按下W键1秒钟使球进入相机视野时,您将看到球根据WASD键应用速度移动。如果移动鼠标,则四元数将应用于Body,并计算正确的速度。 现在转180度,X轴上的旋转现在以某种方式被否定了。 当向上移动鼠标时,球体向下旋转。
如何解决这样的问题?也许我在其他地方做错了什么,可能会影响四元数?
也许我应该提到,在playercontroller(pl.js)中,我将旋转应用于sphereBody,而不是yaw-和pitchObjects。
来自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);

Codepen在Chrome中无法工作,因为pl.js没有正确的MIME类型。在这里修复了它:https://codepen.io/anon/pen/PGGpLZ - schteppe
1个回答

13
问题在于你如何给四元数分配角度。四元数的 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);

专业提示:如果可以避免,请不要使用欧拉角。它们通常会引起更多问题而不是解决问题。


太棒了。 我最初选择了setFromAxisAngle,但我认为乘法会破坏和损坏值,通过两次设置setFromAxisAngle,第二次将覆盖第一次。 这个方法完美无缺。至于速度,我多次阅读过欧拉角的限制和问题,并且应该尽可能避免使用它们。我会记住的。 谢谢;) - Matt DeVenge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接