cube.rotation.set()
, come hai già scoperto, crea una rotazione lungo gli assi locali dell'oggetto. Durante la prima rotazione, diciamo, lungo X, l'asse X locale nelle coordinate del mondo è esattamente uguale all'asse X del mondo. Tuttavia, dopo la rotazione, gli assi Y e Z locali nelle coordinate del mondo non sono più uguali agli assi Y e Z del mondo. Pertanto, le rotazioni successive lungo quegli assi non assomigliano più alle rotazioni lungo gli assi del mondo. Se cambi l'ordine delle rotazioni, di nuovo, solo la prima rotazione avverrà nello spazio locale incidentalmente identico allo spazio mondiale. Tutte le rotazioni successive saranno calcolate nello spazio locale che non è più identico.
Si desidera ruotare l'oggetto tre volte: una volta lungo l'asse X del mondo, una volta lungo l'asse Y del mondo e una volta lungo l'asse Z del mondo. Ma ora sappiamo che tutte le rotazioni avvengono nello spazio locale. La chiave per fare le rotazioni nello spazio mondiale è porre la domanda: "Che aspetto ha questo asse del mondo nello spazio locale del mio oggetto?" Se si può prendere un asse del mondo, esprimerlo come vettore nello spazio locale dell'oggetto e quindi effettuare una rotazione lungo quel vettore, allora si ottiene una rotazione lungo un vettore del mondo, indipendentemente dallo spazio locale specifico.
Diamo integrare questa idea nel vostro violino:
var x = toRadians($("#rotateX").slider("option", "value"));
var y = toRadians($("#rotateY").slider("option", "value"));
var z = toRadians($("#rotateZ").slider("option", "value"));
var rotation = new THREE.Matrix4();
rotation.multiply(new THREE.Matrix4().makeRotationX(x));
var worldYAxis = new THREE.Vector3(0, 1, 0).applyMatrix4(new THREE.Matrix4().getInverse(rotation));
var rotationWorldY = new THREE.Matrix4().makeRotationAxis(worldYAxis, y);
rotation.multiply(rotationWorldY);
var worldZAxis = new THREE.Vector3(0, 0, 1).applyMatrix4(new THREE.Matrix4().getInverse(rotation));
var rotationWorldZ = new THREE.Matrix4().makeRotationAxis(worldZAxis, z);
rotation.multiply(rotationWorldZ);
cube.matrixAutoUpdate = false;
cube.matrix = rotation;
Se si prova questo codice, si noterà che le rotazioni X sono lungo l'asse mondo X quando Y e Z rotazioni sono pari a zero, le rotazioni Y sono lungo l'asse Y del mondo quando la rotazione Z è zero e le rotazioni Z sono sempre lungo l'asse Z.
Ma cosa succede se, dopo aver impostato una X, quindi una Y, quindi una rotazione Z, ruotiamo nuovamente il cursore X? Noterai che la rotazione non è più lungo l'asse X del mondo, ma lungo l'asse X locale. La ragione di ciò è semplice, sebbene la spiegazione del perché sia così potrebbe non esserlo. Con una sola parola: le rotazioni non si spostano. Vedete, le rotazioni X(a) * Y(b) * Z(c) * X(d)
non è in generale uguale a X(a + d) * Y(b) * Z(c)
. Cioè, se giri lungo il mondo X per a
, quindi lungo il mondo Y per , quindi lungo il mondo Z per c
, e poi di nuovo lungo il mondo X per d
, il risultato non è lo stesso della rotazione che avresti ottenuto se avessi ruotato lungo il mondo X entro il a + d
fin dall'inizio. Il motivo è che il "mondo X" all'inizio delle trasformazioni e il "mondo X" alla fine delle trasformazioni sono due vettori diversi, i cui valori dipendono da tutte le trasformazioni fatte fino a questo punto. Pertanto, rappresentano diversi assi di rotazione nello spazio locale.
Cercherò di anticipare la prossima domanda: "Come posso renderlo tale, che non importa quanto muovo i miei cursori a destra e sinistra, l'oggetto ruota sempre solo lungo gli assi del mondo?" La risposta a ciò si basa su ciò che sappiamo già fare rotazioni attorno agli assi del mondo: l'asse del mondo deve essere espresso come un vettore nello spazio locale e la rotazione deve avvenire intorno a quel vettore. Un'implementazione dell'idea segue:
var prevX = 0, prevY = 0, prevZ = 0;
function doRotate() {
var x = toRadians($("#rotateX").slider("option", "value"));
var y = toRadians($("#rotateY").slider("option", "value"));
var z = toRadians($("#rotateZ").slider("option", "value"));
var inverse = new THREE.Matrix4().getInverse(cube.matrix);
var rotation = cube.matrix;
var worldXAxis = new THREE.Vector3(1, 0, 0).applyMatrix4(new THREE.Matrix4().getInverse(rotation));
var rotationWorldX = new THREE.Matrix4().makeRotationAxis(worldXAxis, x - prevX);
rotation.multiply(rotationWorldX);
var worldYAxis = new THREE.Vector3(0, 1, 0).applyMatrix4(new THREE.Matrix4().getInverse(rotation));
var rotationWorldY = new THREE.Matrix4().makeRotationAxis(worldYAxis, y - prevY);
rotation.multiply(rotationWorldY);
var worldZAxis = new THREE.Vector3(0, 0, 1).applyMatrix4(new THREE.Matrix4().getInverse(rotation));
var rotationWorldZ = new THREE.Matrix4().makeRotationAxis(worldZAxis, z - prevZ);
rotation.multiply(rotationWorldZ);
prevX = x;
prevY = y;
prevZ = z;
cube.matrixAutoUpdate = false;
cube.matrix = rotation;
}
violino: https://jsfiddle.net/2whv0e8o/13/
La funzione di cui sopra è vincolata come gestore slide
caso di tutti i cursori: "slide": doRotate
. Ora, se provi a ruotare qua e là, noterai che, indipendentemente dall'orientamento attuale della scatola, lo spostamento del cursore produce sempre rotazioni lungo gli assi del mondo. C'è un avvertimento: i valori dei cursori non rappresentano più angoli di rotazione reali attorno a un particolare asse. Si noterà che la funzione doRotate
applica solo una rotazione delta lungo gli assi del mondo poiché sono attualmente espressi in coordinate locali. Abbiamo raggiunto l'obiettivo di poter applicare rotazioni incrementali eseguite sempre lungo gli assi del mondo, ma abbiamo perso il significato dei valori assoluti dei cursori X, Y e Z. Ma se i valori non significano nulla, cosa può essere usato per salvare la rotazione attuale dell'oggetto come la rotazione? Nella mia esperienza, è meglio conservare la matrice di trasformazione dell'oggetto all'ingrosso. Cioè, invece di provare a salvare tre particolari angoli di rotazione, oltre a un vettore di traslazione, oltre ai parametri di ridimensionamento, basta salvare l'intera matrice come parte dell'oggetto.
Vedere se http://stackoverflow.com/questions/14774633/how-to-rotate-an-object-and-reset-its-rotation-to-zero/14776900#14776900 e http://stackoverflow.com/questions/19385534/rotate-object-around-world-axis/19386917 # 19386917 aiutarti. – WestLangley
Test ... ... Ho pensato che funzionasse quando ho cambiato il codice da cube.rotation.set (x, y, z, 'XYZ'); a cube.rotation.set (x, y, z, 'ZYX'); ma ha semplicemente spostato il problema su un asse diverso. – Kolban
Aggiunto un jsFiddle per illustrare. – Kolban