基于四元数的炮身正确旋转处理?

Mat*_*nge 5 javascript three.js cannon.js

这个让我很烦恼。我正在尝试根据鼠标输入实现 Cannon.Body 的旋转。用(大炮)三FPS的例子来演示一下,就可以看出是什么问题了。

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

当您运行代码并通过单击“单击播放”区域启用指针锁定控件并按 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);
};
Run Code Online (Sandbox Code Playgroud)

和(第 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;
Run Code Online (Sandbox Code Playgroud)

在 animate() 函数中,codepen(第 305 行): testballMesh.position.copy(sphereBody.position); testballMesh.quaternion.copy(sphereBody.quaternion);

sch*_*ppe 12

问题在于您为四元数指定角度和从四元数指定角度的方式。四元数 x,y,z,w 属性与角度不直接兼容,因此您需要进行转换。

这是如何为CANNON.Quaternion设置围绕给定轴的角度

var axis = new CANNON.Vec3(1,0,0);
var angle = Math.PI / 3;
body.quaternion.setFromAxisAngle(axis, angle);
Run Code Online (Sandbox Code Playgroud)

从四元数中提取欧拉角可能不是解决问题第二部分的最佳方法。当用户移动鼠标时,您可以只存储围绕 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 ) );
Run Code Online (Sandbox Code Playgroud)

然后将旋转作为四元数,分别使用两个四元数(一个用于 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();
Run Code Online (Sandbox Code Playgroud)

将四元数应用于速度向量:

var rotatedVelocity = quaternion.vmult(inputVelocity);
Run Code Online (Sandbox Code Playgroud)

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