Unexpected results with Three.js setFromRotationMatrix when rotation exceeds 90 degrees

Each of my objects has a unique parent for X-rotation, Y-rotation, and Z-rotation. They are all interconnected in a specific order: the X-rotation object is a child of the Y-rotation object, while the Y-rotation object is a child of the Z-rotation object.

I am working on implementing a feature that allows users to rotate all objects in the scene simultaneously (contained within a single Object3D). When this main Object3D is rotated, the program needs to calculate each object's absolute position and rotation relative to the world so that it can output new values for each object accordingly.

To achieve this, I have set up the objects to move their position inside the "scene-rotator", which is an Object3D, to be their absolute position relative to the world. Now, I am trying to ensure that the rotation of each object reflects its absolute rotation relative to the world, adjusting as the "scene-rotator" is rotated. Due to issues with the setFromRotationMatrix method, I had to run it separately for each parent object to accurately retrieve the rotations.

The following code snippet captures how I aim to determine 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(); 
beforeRotForY.setFromRotationMatrix(objects[i].parent.parent.matrixWorld, "ZYX");

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

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

Subsequently, the program should apply the calculated absolute rotation to each object's relative rotation:

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;

While this process works correctly when the Y-rotation of the second parent falls within -90 through 90 degrees, it does not yield accurate results if the Y-rotation exceeds these bounds:

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

Answer №1

The issue you're encountering is known as gimbal lock. When utilizing euler angles, it's common to face gimbal lock problems which result in unexpected behavior when applying multiple rotations.

For instance, in a 2D space, a 30° rotation is equivalent to a -330° rotation. Similarly, in 3D space, rotating an object 180° along the X-axis is the same as giving it a 180° Y-axis + 180° Z-axis rotation.

To avoid gimbal lock issues, it's recommended to define your rotations using quaternions and then combine them to achieve the desired outcome seamlessly.

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

// Defining 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);

// Initializing quaternions for each axis
var quatX = new THREE.Quaternion();
var quatY = new THREE.Quaternion();
var quatZ = new THREE.Quaternion();

// Setting 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));

// Multiplying quaternions to obtain final rotation
quatY.multiply(quatX);
quatZ.multiply(quatY);

// Applying the multiplied rotation to your mesh
mesh.quaternion.copy(quatZ);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Struggles encountered while developing a JavaScript calendar

Hey guys, I'm encountering an issue with Uncaught TypeError: document.getElementById(...) is null. I believe the problem lies in the way types are being parsed for document.getElementById(dayOfWeek).appendChild(dayPTag);. This code is meant to display ...

Show Pagination of Items on the Screen

I am dealing with an Array of Objects: const myArray = [ {myObject: "1"}, {myObject: "2"}, {myObject: "3"}, {myObject: "4"}, {myObject: "5"}, ] To implement a pagination system for thes ...

Flask encountering an unexpected error while sending an ajax request, despite the fact that a duplicate request from another function is functioning properly

As a novice in Python and Flask, I have found it incredibly helpful to use them for running a webapp on my Raspberry Pi. Initially, I developed the app in HTML with JavaScript handling the logic. Now that I have a "finished" app, I am looking to enhance i ...

Looping through nested arrays in an array of objects with Angular's ng-repeat

I'm struggling to access an array within an array of objects in my AngularJS project. Here's the HTML: <li ng-repeat="ai in main.a2"> <div np-repeat="bi in ai.b"> <span ng-bind="bi"></span>b2 </div> </l ...

Tracking the progress of reading position using Jquery within an article

Here is an example of a reading progress indicator where the width increases as you scroll down the page: http://jsfiddle.net/SnJXQ/61/ We want the progress bar width to start increasing when the article content div reaches the end of the article c ...

Clicking the delete button in Firebase to remove an item

I am in the process of developing a simple CRUD application and have opted for Firebase as my backend solution. While I have successfully implemented the create and read functionalities, I've hit a roadblock with the delete operation. When attempti ...

Every time I refresh the page, my table is getting filled with blank rows

I created a simple example featuring a form and some PHP/JavaScript code. The JavaScript is used for form validation, while the PHP is utilized to update a MySQL table. function checkForm(){ var x = document.forms['form1']['first'] ...

Do you mean using a JSON object as a value?

When creating a JSON object where the value itself is an object, what is the correct way to write it? var data ='{"phone":{"gtd": "080"}}'; OR var data ='{"phone":"{gtd: 080}"}'; This question may seem straightforward. I am curious ...

Creating a Multi-stop Gradient Effect on Lines in THREE.js

Learn how to create a stunning two-color gradient effect on a THREE.js line with this helpful guide: Color Gradient for Three.js line Have you ever wondered how to achieve a multi-stop color gradient along a line in THREE.js? Find out the solution here - ...

What is the best way to showcase two SVG clocks on a single webpage?

The issue arises when combining the desktop and mobile versions of the clock script. The first clock works fine on its own, but upon duplicating another set of scripts for the second clock, it encounters display problems. I have appropriately labeled the c ...

Is it possible to utilize onclick for various table cells in jQuery?

I have a situation where I need to loop through dates and display table content accordingly. Could someone please assist me in figuring out how to do this? index.html.erb <% @batches.each do |batch| %> <tr> **<td class = "pie" id ...

Remove any nulls or undefined values from the object

I have developed a custom function that eliminates null and undefined values from an object. However, it seems to be mistakenly removing keys where the value is 0 as well. For instance: { key1: 'value1', key2: 0 } Even though it shouldn&ap ...

Angular Bootstrap uibModal is failing to resolve attributes

Issue with Roles in AngularJS Bootstrap uiModel var modalInstance = $uibModal.open({ animation: $scope.animationsEnabled, templateUrl: 'myModalContent.html', controller: 'ModalInstanceCtrl', size: 100, resolve: { roles: f ...

Combining vueJS and webpack to bring in fonts, CSS styles, and node_modules into your project

I've recently started working with Vue.js and Webpack, and I'm facing some challenges regarding the correct way to import and reference fonts, CSS, and node_modules in my project. My project structure looks like this, as set up by vue-cli: buil ...

Nodeca's js-yaml now allows appending '>-' to handle extended strings with ease

With the npm package js-yaml, I am attempting to work with a .yaml file. Although I can manipulate it successfully, I encounter an issue when trying to save a long string. Actual: abvs_adas: >- c2Rhc2Rhc2Rhc2Rhc2RwaW9qbGtkZ2hqbGtzZGhmZ2psaGFzamh ...

Steps to initiate my selenium-standalone server: Execute the command "selenium-standalone start"

I'm currently facing a challenge while trying to execute a test script in WebDriverIO. After cloning the code from wdio-cucumber-framework, I am unable to get selenium-standalone to start properly. The error message indicates an issue with geckodriv ...

What is the procedure for adding a data table to an HTML table with JSON?

I'm trying to display a table fixture layout in an HTML table using the Ajax method, but it's not working. I'm not sure what the problem is. Can someone please help me out with my code? Controller JsonResult public JsonResult FixturesVal( ...

Having difficulty retrieving information from Redux store

In my project, I utilize the Redux store to manage data. Through Redux-DevTools, I can observe that initially the data is null but upon refreshing the page, the data successfully populates the store. However, when attempting to retrieve this data within on ...

What could be causing my recursive function to skip over certain parts of my JSON data?

UPDATED TO BE MORE CONCISE Hello, I'm looking for assistance with a recursive function that's not returning the expected values from a JSON object. The goal is to retrieve all "Flow" object IDs where the "Type" is either "Standard" or "Block". T ...

Unable to set the height for ul/div elements

I'm struggling to make my navbar appear when I click the "menu button". The div seems to be present in the code, but with a height of 0. Here's the relevant section of the code causing the issue. Any suggestions on how I can resolve this? var ...