【问题标题】:Handling Proper Rotation of Cannon Body Based on Quaternion?基于四元数处理炮体的正确旋转?
【发布时间】:2016-09-20 22:23:22
【问题描述】:

这个问题让我很烦。 我正在尝试根据鼠标输入实现 Cannon.Body 的旋转。 通过使用(Cannon)3 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);
};

并且(第 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);

【问题讨论】:

标签: javascript three.js cannon.js


【解决方案1】:

问题在于您为四元数分配角度的方式。四元数 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 两次,第二个会覆盖第一个。不过,这完美无缺。至于速度,我确实多次读到欧拉有局限性和问题,如果可能的话应该避免它们。我会牢记这一点,以备将来之用。谢谢;)
猜你喜欢
  • 1970-01-01
  • 2016-09-03
  • 2018-11-17
  • 2020-11-06
  • 1970-01-01
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
  • 2019-04-06
相关资源
最近更新 更多