8

我有对象,每个对象对于每个旋转轴都有一个单独的父对象(1 个用于 X 旋转,1 个用于 Y 旋转,1 个用于 Z 旋转。它们也都按该顺序相互关联:X 旋转对象是 Y 旋转对象的子对象。Y 旋转对象是 Z 旋转对象的子对象)。

我正在尝试制作一个功能,允许用户一起旋转场景中的所有对象(它们都包含在单个 Object3D 中)。当 Object3D 旋转时,程序必须找到所有对象相对于世界的绝对位置和旋转,以便程序可以为每个对象输出新值。

为此,我目前将其设置为移动对象,以便将其在“场景旋转器”(一个 Object3D)内的位置设置为相对于世界的绝对位置。现在,我试图让物体的旋转成为物体相对于世界的绝对旋转,这样当“场景旋转器”的旋转改变时,它也会相应地改变。此外,当我尝试在子对象上运行一次 setFromRotationMatrix 方法时,它无法正常工作,因此,我不得不为每个父对象再次运行它并相应地从它们中获取每个单独的旋转

这是我目前拥有的代码,它应该获得对象相对于世界的绝对旋转:

var beforeRotForX = new THREE.Euler();
beforeRotForX.setFromRotationMatrix(objects[i].parent.matrixWorld, "ZYX");

var beforeRotForY = new THREE.Euler(); // Had to be a separate one for some reason...
beforeRotForY.setFromRotationMatrix(objects[i].parent.parent.matrixWorld, "ZYX");

var beforeRotForZ = new THREE.Euler(); // And apparently this one has to be separate too
beforeRotForZ.setFromRotationMatrix(objects[i].parent.parent.parent.matrixWorld, "ZYX");

// Absolute before rotation
objects[i].userData.sceneBeforeRotAbs = {
    x: beforeRotForX.x,
    y: beforeRotForY.y,
    z: beforeRotForZ.z
};

然后,它必须将该绝对旋转应用于对象的相对旋转

objects[i].parent.rotation.x = objects[i].userData.sceneBeforeRotAbs.x;
objects[i].parent.parent.rotation.y = objects[i].userData.sceneBeforeRotAbs.y;
objects[i].parent.parent.parent.rotation.z = objects[i].userData.sceneBeforeRotAbs.z;

当第二个父母的 Y 旋转在 -90 到 90 之间时,这一切都很好

// Results of absolute world rotation when the Y-rotation of the
// second parent is set to 90 degrees (1.5707... as euler)
objects[i].userData.sceneBeforeRotAbs.x === 0
objects[i].userData.sceneBeforeRotAbs.y === 1.5707963267948966
objects[i].userData.sceneBeforeRotAbs.z === 0

但是当第二个父节点的 Y 旋转低于 -90 或大于 90 时,它会因此为绝对世界 X 旋转和 Y 旋转给出错误的值

// Results of absolute world rotation when the Y-rotation of the
// second parent is set to 91 degrees (1.5882... as euler)
objects[i].userData.sceneBeforeRotAbs.x === 3.141592653589793
objects[i].userData.sceneBeforeRotAbs.y === 1.5533438924131038
objects[i].userData.sceneBeforeRotAbs.z === 0
4

1 回答 1

5

你遇到了万向节锁。使用欧拉角时,您总是会遇到万向节锁定问题,并且在应用多次旋转时会遇到意外行为。

例如,在 2D 空间中,30° 旋转与 -330° 旋转相同。在 3D 空间中,您可能会遇到同样的问题:将对象在 X 轴上旋转 180° 与将其旋转 180° Y 轴 + 180° Z 轴旋转相同。

您应该使用quaternions声明您的旋转,然后将它们相乘以获得所需的结果,而不会出现万向节锁定问题。

// Declare angles
var angleX = 45;
var angleY = 120;
var angleZ = 78;

// Declare X and Y axes
var axisX = new THREE.Vector3(1, 0, 0);
var axisY = new THREE.Vector3(0, 1, 0);
var axisZ = new THREE.Vector3(0, 0, 1);

// Init quaternions that will rotate along each axis
var quatX = new THREE.Quaternion();
var quatY = new THREE.Quaternion();
var quatZ = new THREE.Quaternion();

// Set quaternions from each axis (in radians)...
quatX.setFromAxisAngle(axisX, THREE.Math.degToRad(angleX));
quatY.setFromAxisAngle(axisY, THREE.Math.degToRad(angleY));
quatZ.setFromAxisAngle(axisZ, THREE.Math.degToRad(angleZ));

// ...then multiply them to get final rotation
quatY.multiply(quatX);
quatZ.multiply(quatY);

// Apply multiplied rotation to your mesh
mesh.quaternion.copy(quatZ);
于 2017-05-18T19:30:11.100 回答