2016-03-19 14 views
7

Ho oggetti che hanno ciascuno un padre separato per ciascun asse di rotazione (1 per rotazione X, 1 per rotazione Y e 1 per rotazione Z. tutti correlati tra loro in quell'ordine: L'oggetto rotazione X è figlio dell'oggetto di rotazione Y. L'oggetto rotazione Y è figlio dell'oggetto rotazione Z).Three.js setFromRotationMatrix comportamento strano quando la rotazione è superiore a 90 gradi

Sto cercando di creare una funzionalità che consenta agli utenti di ruotare tutti gli oggetti nella scena (sono tutti contenuti in un singolo Object3D). Quando quell'oggetto Object3D viene ruotato, il programma deve trovare tutte le posizioni e rotazioni assolute degli oggetti relative al mondo in modo che il programma possa emettere i nuovi valori per ciascun oggetto.

Per fare ciò, attualmente l'ho configurato per spostare l'oggetto in modo che la sua posizione all'interno di "scene-rotator", che è Object3D, sia impostata sulla sua posizione assoluta rispetto al mondo. Ora, sto cercando di fare in modo che la rotazione dell'oggetto diventi la rotazione assoluta dell'oggetto rispetto al mondo, in modo che cambi di conseguenza quando la rotazione del "rotatore di scena" viene cambiata. Inoltre, il metodo setFromRotationMatrix non funzionava correttamente quando ho provato a eseguirlo solo una volta sull'oggetto figlio, quindi, dovevo eseguirlo di nuovo per ogni oggetto padre e ottenere ciascuna rotazione separata di conseguenza

Questo è il codice che ho attualmente che si suppone per ottenere la rotazione assoluta dell'oggetto rispetto al mondo:

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

Poi, si deve applicare che la rotazione assoluta alla relativa rotazione dell'oggetto

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; 

Questo tutto funziona bene quando Y-rotazione del secondo genitore è a -90 e 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 

ma quando Y-rotazione del secondo genitore è inferiore a -90 o maggiore di 90, allora si dà il valore errato per l'assoluta mondo X-rotazione e Y-rotazione a seguito

// 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 
+2

Ho letto il tuo problema dscription 2 volte e non riesco davvero a capire cosa stai cercando di ottenere. Ma una cosa che mi colpisce è il problema nel ruotare le cose attorno a tutti gli assi con gli angoli di Eulero. Quando si verifica un comportamento strano dalla rotazione con gli angoli di Eulero, ciò potrebbe essere dovuto a un [Blocco Gimbal] (https://en.wikipedia.org/wiki/Gimbal_lock). Vorrei raccomandare di provare questo utilizzando quaternioni invece. Three.js li supporta anche io – micnil

+0

Riesco a vedere cosa intendi perché potrebbe sembrare ridondante fare tutto questo, ma per riferimento, questa è la pagina a cui è destinata: https://mrgarretto.com/model/ ed è uno strumento per le persone da utilizzare che deve essere in grado di generare varie cose dopo che l'utente ha realizzato un progetto con esso. Ecco un album che ho messo insieme che potrebbe aiutare a mostrare il problema in azione: http: // imgur.com/a/jkTeo Proverò a usare i quaternioni e vedere se questo risolve il problema – MrGarretto

risposta

0

si sta eseguendo in gimbal lock. Quando usi gli angoli di euler, ti imbatterai sempre in problemi di blocco cardanico e incontrerai un comportamento inaspettato quando applichi più rotazioni.

Ad esempio, nello spazio 2D, una rotazione di 30 ° è la stessa di una rotazione di -330 °. Nello spazio 3D, puoi ottenere lo stesso problema: ruotare un oggetto di 180 ° sull'asse X equivale a dare un asse Y a 180 ° e una rotazione dell'asse Z a 180 °.

È necessario dichiarare le rotazioni utilizzando quaternions e quindi moltiplicarle per ottenere il risultato desiderato senza problemi di blocco del giunto cardanico.

// 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); 
Problemi correlati