MrG*_*tto 8 javascript parents euler-angles degrees three.js
我有每个旋转轴都有一个单独父对象的对象(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
};
Run Code Online (Sandbox Code Playgroud)
然后,它必须将该绝对旋转应用于对象的相对旋转
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;
Run Code Online (Sandbox Code Playgroud)
当第二个父级的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
Run Code Online (Sandbox Code Playgroud)
但是当第二个父级的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
Run Code Online (Sandbox Code Playgroud)
You're running into gimbal lock. When using euler angles you'll always run into gimbal lock issues, and you'll encounter unexpected behavior when applying multiple rotations.
For example, in 2D space, a 30° rotation is the same as a -330° rotation. In 3D space, you can get the same problem: rotating an object 180° in the X-axis is the same as giving it a 180° Y-axis + 180° Z-axis rotation.
You should declare your rotations using quaternions, and then multiply them together to get the desired result without gimbal lock issues.
// 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);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
832 次 |
| 最近记录: |