Come posso ruotare su un punto arbitrario in 3D (anziché l'origine)?


15

Ho alcuni modelli che voglio ruotare usando i quaternioni in modo normale, tranne che invece di ruotare attorno all'origine, voglio che sia leggermente sfalsato. So che non dici, nello spazio 3d, che ruoti di un punto; dici di ruotare attorno ad un asse. Quindi lo sto visualizzando come ruotante attorno a un vettore la cui coda non è posizionata sull'origine locale.

Tutte le trasformazioni affini nel mio motore di rendering / fisica sono memorizzate usando SQT (scala, quaternione, traduzione; un'idea presa in prestito dal libro Game Engine Architecture .) Quindi costruisco una matrice ogni frame da questi componenti e la passo allo shader di vertice. In questo sistema, viene applicata la traduzione, quindi la scala, quindi la rotazione.

In un caso specifico, devo tradurre un oggetto nello spazio del mondo, ridimensionarlo e ruotarlo su un vertice non centrato sull'origine locale dell'oggetto.

Domanda: dati i vincoli del mio attuale sistema sopra descritti, come posso ottenere una rotazione locale centrata su un punto diverso dall'origine? Voto automatico a chiunque possa descrivere come fare usando solo matrici :)


I quaternioni descrivono già una rotazione attorno ad un asse arbitrario; hai problemi a costruire un tale quaternione dai dati che hai?
Martin Sojka,

3
Seriamente, le persone che hanno votato le risposte potrebbero davvero leggerle ? Ho dato un metodo, una formula efficace e persino una dimostrazione. Tuttavia l'unica risposta votata, pur fornendo alcune informazioni preziose (e anche alcune informazioni chiaramente sbagliate), non presenta nessuna di queste e non risponde nemmeno alla domanda!
sam hocevar,

@MartinSojka, questo è circa e punto arbitrario, non un asse arbitrario.
notlesh

@SamHocevar Entrambe le tue risposte sono state utili. Ho scelto il tuo perché era più accurato e mi ha aiutato a trovare una soluzione. Grazie ad entrambi.
notlesh

Ah, scusa, l'ho confuso con Dual Quaternions (anche quelli ti danno la traduzione "gratis"). Scriverò cosa intendevo in una risposta più tardi; forse altri lo troverebbero utile, soprattutto perché puoi ridurre i tuoi tre componenti a uno solo, anche se un po 'più complesso.
Martin Sojka,

Risposte:


17

In breve

Devi solo cambiare T nel tuo modulo SQT.

Sostituisci il vettore di traduzione vcon v' = v-invscale(p-invrotate(p))dove si vtrova il vettore di traduzione iniziale, pè il punto attorno al quale desideri che avvenga la rotazione invrotatee invscalesiano gli inversori della rotazione e della scala.

Dimostrazione veloce

Lascia che psia il punto attorno al quale applicare la rotazione r. Lascia che ssiano i parametri di ridimensionamento e vil vettore di traduzione. La trasformazione finale della matrice è T(p)R(r)T(-p)S(s)T(v)invece di R(r)S(s)T(v).

Quello che vuoi è nuovi parametri di trasformazione v', r'e s'in modo tale che la trasformazione di matrice finale è R(r')S(s')T(v')e noi abbiamo:

T(p)R(r)T(-p)S(s)T(v) = R(r')S(s')T(v')

Il comportamento all'infinito indica che i parametri di rotazione e di ridimensionamento non possono cambiare (questo potrebbe essere dimostrato). Abbiamo quindi r = r'e s = s'. L'unico parametro mancante è quindi il v'tuo nuovo vettore di traduzione:

T(p)R(r)T(-p)S(s)T(v) = R(r)S(s)T(v')

Se queste matrici sono uguali, i loro inversi sono uguali:

T(-v)S(-s)T(p)R(-r)T(-p) = T(-v')S(-s)R(-r)

Questo vale soprattutto per l'origine O:

T(-v)S(-s)T(p)R(-r)T(-p)O = T(-v')S(-s)R(-r)O

Il ridimensionamento e la rotazione dell'origine produce l'origine, ottenendo così:

T(-v)S(-s)T(p)R(-r)(-p) = -v'

v'è il nuovo vettore di traduzione che stai cercando che ti consente di memorizzare la trasformazione in formato SQT. È probabilmente possibile semplificare il calcolo; ma almeno lo spazio di archiviazione richiesto non è aumentato.


Grazie per la spiegazione. A proposito, conosci qualche risorsa dove potrei leggere di più sui trucchi di rappresentazione SQT?
Pachanga,

Correggimi se sbaglio, ma sembra un'altra soluzione sarebbe quella di memorizzare il tuo Quaternion normalmente, e se hai bisogno di rendere conto della traduzione attorno a un punto / asse arbitrario, quindi costruire la matrice Q con questa inclusa, estrarre semplicemente il vettore di traduzione da questa matrice (ultima colonna, di solito) e aggiungila al vettore di traduzione degli oggetti, quindi lancia la tua matrice temporanea.
johnbakers,

15

Tutte le formule di rotazione canoniche utilizzate per derivare le matrici di rotazione sono per la rotazione attorno all'origine. Se invece desideri applicare quella rotazione attorno a un punto specifico, devi prima compensare l'origine o, equivalentemente, spostare l'oggetto in modo che il punto su cui vuoi ruotare sia all'origine.

Considera prima il caso 2D, perché è più semplice e la tecnica si ridimensiona. Se avessi un cubo di larghezza 2 centrato sull'origine e volessi ruotarlo di 45 gradi attorno al suo centro, sarebbe una banale applicazione della matrice di rotazione 2D .

Ma se invece volessi ruotarlo attorno all'angolo in alto a destra (situato in 1,1), dovresti prima tradurlo in modo che quell'angolo fosse all'origine. Questo può essere realizzato con una traduzione di -1,-1. Quindi puoi ruotare l'oggetto come prima, ma devi seguirlo traducendolo indietro (di 1,1). Quindi, in generale, per ottenere la matrice di rotazione Rper una rotazione di rcirca il punto Psi fa:

R = translate(-P) * rotate(r) * translate(P)

dove translatee rotatesono le matrici di traduzione / rotazione canoniche, rispettivamente. A quanto pare, questo si ridimensiona in modo banale rispetto al 3D, che a parte il fatto di dover fornire un asse anche alla rotazione - potresti sempre scegliere le matrici di rotazione degli assi X, Y o Z canoniche, ma sarebbe noioso. Ti consigliamo di utilizzare la matrice di rotazione arbitraria dell'angolo dell'asse . Il tuo finale Rin 3D è quindi:

R = translate(-P) * rotate(a,r) * translate(P)

dove aè un vettore unitario che rappresenta l'asse di rotazione e Pora è un punto 3D nello spazio modello che rappresenta il punto di rotazione.

In questo caso, i quaternioni possono essere convertiti in e da rappresentazioni di matrici, in modo che tu possa fare la tua concatenazione in quel modo se lo desideri. Oppure potresti semplicemente lasciare tutto come matrici (i quaternioni hanno alcuni bei vantaggi come essere più facili da interpolare in modo sano, ma se hai bisogno o no dipende da te).

Anche:

Quindi lo sto visualizzando come ruotante attorno a un vettore la cui coda non è posizionata sull'origine locale.

A rigor di termini, mentre i vettori possono essere usati per rappresentare posizioni considerandole come spostamenti da un'origine, i vettori non hanno posizioni stesse, quindi è un po 'insolito visualizzarne una come tale.


Grazie, questa è una buona risposta. Tuttavia, non si adatta ai vincoli del mio sistema. Avrei dovuto includere nella mia domanda "è possibile farlo alla luce di questi vincoli?" E penso che la risposta sia che non lo è, dal momento che ciò richiede due traduzioni e ne prevedo solo una. Si tratta di una inevitabile lacuna dell'uso di SQT come rappresentazione delle trasformazioni affine?
notlesh

Si adatta perfettamente ai tuoi vincoli. La matrice R (prodotta come translate-rotate-translate-back) è la tua matrice di rotazione. Sostituisci Q con R nel tuo sistema "SQT" in modo da avere il paradigma più comune di scala-rotazione-traduzione e il gioco è fatto. L'ultima traduzione è indipendente dalle due traduzioni intermedie eseguite per produrre la rotazione desiderata.

Stai proponendo di sostituire il quaternione con una matrice? Sono 12 byte in più per oggetto (8 se lo memorizzo come matrice 4x3)! Silenzierò l'ottimista in me, tuttavia, e darò un vortice. (Questo in realtà probabilmente non equivarrà nemmeno a un aumento di 2kb dell'impronta ...) Grazie per le risposte.
notlesh

Potresti - potresti anche convertirti tra loro, costruendo il quaternione di rotazione in quel modo e ricollegando il sistema esistente.

1
@SamHocevar: in alternativa, qualsiasi combinazione di questi può essere espressa come una singola vite .
Martin Sojka,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.