Three.js setFromRotationMatrix weird behavior when rotating over 90 degrees

I have objects, each of which has a separate parent for each axis of rotation (1 for X-rotation, 1 for Y-rotation and 1 for Z-rotation. All of them are also related to each other in this order: X -rotation Object is a child of Y-rotation, and a object of Y-rotation is a child of Z-rotation.

I am trying to create a function that allows users to rotate all objects in a scene together (they are all contained in one 3D object). When this Object3D is rotated, the program must find all the absolute positions and rotations of the objects relative to the world so that the program can output new values ​​for each object.

To do this, I currently have a setting for moving the object so that its position inside the "scene-rotator", which is the Object3D object, is set to its absolute position relative to the world. Now I am trying to make the rotation of the object become the absolute rotation of the object with respect to the world, so that it changes accordingly when the rotation "scene rotation" changes. In addition, the setFromRotationMatrix method did not work correctly when I tried to just run it once on a child, so instead I had to run it again for each parent object and get every single rotation from it.

This is the code I have that should get the absolute rotation of the object relative to the world:

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 }; 

Then he must apply this absolute rotation to the relative rotation of the object.

 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; 

All this works great when the second parent's Y-rotation is between -90 and 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 

but when the second parent's Y-rotation is below -90 or greater than 90, then it gives the wrong value for the absolute world X-rotation and Y-rotation as a result

 // 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 
+7
javascript euler-angles parents
source share
1 answer

You are using gimbal lock . When using Euler angles, you always encounter problems with locking the driveshaft, and when applying several turns you will encounter unexpected behavior.

For example, in a 2D space, a rotation of 30 Β° coincides with a rotation of -330 Β°. In three-dimensional space, you can get the same problem: rotating an object 180 Β° along the X axis is the same as rotating it along the Y axis 180 Β° + 180 Β°.

You must declare your rotations using quaternions , and then multiply them together to get the desired result without any problems with locking the cardan.

 // 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 axisY = 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); 
0
source share

All Articles