2016-06-19 28 views
7

Aggiornamento: Aggiunto un jsfiddle per illustrare:Impostare la rotazione assoluta di un oggetto in tutto il mondo all'asse

JSFiddle

Ho un oggetto (un cubo) che è posto nella scena. Il mio obiettivo è quello di fornire 3 angoli che rappresentano l'orientamento di un oggetto nel mondo reale. Gli angoli saranno misurati rispetto all'asse X, Y e Z del mondo reale. Quello che sto fallendo (miseramente) è come dare un oggetto a questi angoli e poi quando i dati cambiano, imposta l'oggetto in modo che riceva una nuova tripletta di angoli. Quello che mi sembra di trovare è che quando imposto una serie iniziale di angoli, tutto va bene, ma quando imposto una nuova serie di angoli, sembrano essere relativi all'orientamento dello spazio dell'oggetto locale rispetto allo spazio mondiale. Ho cercato di capire alcune delle domande simili poste in quest'area, ma queste sembrano riguardare la rotazione di un oggetto attorno a un asse anziché l'impostazione di un oggetto in modo esplicito contro l'asse del mondo.

Quando un valore di My X, angolo cambia Y o Z, Attualmente sto chiamando:

cube.rotation.set(x, y , z, 'XYZ'); 

Per illustrare ulteriormente, ecco un colpo di schermo mia cubo ... senza cambiare X o Y, ruoto 90 su Z ... vedere le due immagini di prima e dopo

enter image description here

e

enter image description here

Si noti come si è verificato la rotazione intorno alla direzione della normale della faccia viola e non attorno all'asse mondo Z ...

stumped :-(

+0

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

+0

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

+0

Aggiunto un jsFiddle per illustrare. – Kolban

risposta

1

È necessario aggiungere un punto di svolta per la scena, questo sarà il centro delle rotazioni. Il cubo di poltiglia deve essere aggiunto al punto di rotazione e quindi è possibile ruotare il punto di rotazione.

Ho aggiornato la tua jsFiddle qui: https://jsfiddle.net/x5w31f33/

var cube = new THREE.Mesh(geometry, material); 
cube.position.set(2, 0, 0); 

var pivotPoint = new THREE.Object3D(); 
scene.add(pivotPoint); 
pivotPoint.add(cube); 

pivotPoint.rotation.set(x, y , z, 'XYZ'); 
3

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.