Specchi di rotazione slerping


9

Ruoto il mio personaggio di gioco per guardare il bersaglio usando il seguente codice:

        transform.rotation = Quaternion.Slerp(startQuaternion, lookQuaternion, turningNormalizer*turningSpeed/10f)

startQuaternion è la rotazione corrente del personaggio quando viene dato un nuovo bersaglio.

lookQuaternion è la direzione in cui il personaggio dovrebbe guardare ed è impostato in questo modo:

    destinationVector = currentWaypoint.transform.position - transform.position;
    lookQuaternion = Quaternion.LookRotation(destinationVector, Vector3.up);

turningNormalizer è appena Time.deltaTimeincrementato ed turningSpeedè un valore statico indicato nell'editor.

Il problema è che mentre il personaggio gira come dovrebbe per la maggior parte del tempo, ha problemi quando deve fare quasi 180 gradi. Quindi a volte si agita e rispecchia la rotazione:

inserisci qui la descrizione dell'immagine

In questa immagine mal disegnata il personaggio (a destra) inizia a girare verso il cerchio a sinistra. Invece di girare semplicemente a sinistra oa destra, inizia questa "danza dello specchio":

  1. Inizia a ruotare verso il nuovo fronte
  2. Quindi improvvisamente scatta con la stessa angolazione ma dall'altro lato e continua a ruotare

Fa questo "mirroring" così a lungo fino a quando non guarda il bersaglio. È una cosa con quaternioni, slerping / lerping o qualcos'altro?

EDIT1: Apparentemente il problema non deriva dalla rotazione stessa. Il problema più probabile è che il personaggio si sposta verso il fronte mentre ruota. Come limitare l'angolo, tra il fronte e il bersaglio, quando il personaggio è autorizzato a muoversi riduce ed a volte elimina la rotazione del jitter / mirroring.

Questo ovviamente solleva più domande, perché il personaggio non può muoversi e ruotare contemporaneamente senza problemi? Codice utilizzato per il movimento:

transform.Translate(Vector3.forward * runningSpeed/10f * Time.deltaTime);

'LookQuaternion' viene aggiornato ogni frame? Se è così, allora la mia presunzione sarebbe che alcune piccole imprecisioni stanno portando a una sorta di jitter in cui il giocatore "supera" la rotazione dello sguardo e quindi la nuova direzione di guardare è proprio dall'altra parte di "direttamente dietro" ... .
Steven Stadnicki

Risposte:


5

Ogni orientamento nello spazio 3D può essere rappresentato da 2 quaternioni di unità distinte qe -q(negato dal punto di vista dei componenti q). Ad esempio l'orientamento rappresentato dalla matrice di identità 3x3 Ipuò essere rappresentato da 2 quaternioni:

 q:  { 0,  0,  0},  1
-q:  {-0, -0, -0}, -1

Entrambi rappresentano lo stesso orientamento nello spazio 3D, il loro prodotto punto è esattamente -1, ognuno dei quali si trova nell'altro emisfero, esattamente sui lati opposti dell'ipersfera.

Il risultato che si osserva quando lo slerp impiega l'arco più lungo a ruotare, è quando si esegue lo slerping tra 2 quaternioni che non si trovano nello stesso emisfero. Se ciò accade, negane uno solo prima di eseguirli, quindi lo slerp prenderà l'arco più corto.

Il prodotto punto è uno strumento semplice per scoprire se ciò accade. Se il prodotto punto di entrambi i quaternioni è inferiore a 0, allora non si trovano nello stesso emisfero. Quindi, se il prodotto punto di entrambi è inferiore a 0, solo componente saggio nega l'altro quaternione prima di slerping.


Mi chiedo se ti ho capito correttamente come l'ho provato con questo, if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Inverse(startQuaternion); }ma non ha risolto il problema. Scusate per la scarsa formattazione, non riesco a domare questa sezione dei commenti.
Esa,

Quasi, ma non Inverseè un'operazione diversa da Negate. if(Quaternion.Dot (lookQuaternion, q) < 0) { q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w; }Non uso C #, ma dall'aspetto del documento sembra che tu possa anche usare direttamente la Funzione Negata .
Maik Semder,

if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Negate(startQuaternion); }
Maik Semder,

Temo che questi non abbiano risolto il problema. Ho aggiornato la domanda.
Esa,

Sì, probabilmente è un mix di diversi bug. Semplifica la configurazione del test, testa una cosa alla volta, non traslazione e rotazione contemporaneamente. Prima assicurati che uno funzioni, poi l'altro e poi entrambi insieme. Concentrati prima solo sulla rotazione, usa alcuni valori di orientamento ben noti, come iniziare a 170 gradi, spostarsi verso il basso a zero, vedere dove va storto e pubblicarlo qui
Maik Semder

1

Bene, il tuo problema è perché quei due vettori che formano i tuoi quaternioni fanno 180 gradi, quindi la domanda che dovrebbe essere posta quando si interpola quale arco dovrebbe prendere? l'arco superiore o quello inferiore ??

Questo è ciò che fondamentalmente causa il mirroring, ogni volta che si interpola si sta facendo il contrario, mantenendo comunque l'angolo.

Secondo questo link .

Quando theta è di 180 gradi il risultato non è definito perché non esiste una direzione più breve da ruotare, non penso che questa situazione sia gestita correttamente, sarebbe meglio se scegliamo un asse arbitrario normale a qa o qb, vorrei apprezzare le idee per il modo migliore per farlo.

Quello che devi fare è interpolare il tuo quaternione iniziale con un quaternione intermedio (per determinare quale arco prendere) e quando raggiunto usa il quaternione intermedio per continuare al quaternione bersaglio effettivo.


1

Il problema che sospetto che stai vedendo non ha nulla a che fare con il tuo codice, ma piuttosto è un problema fondamentale con l'interpolazione lungo la superficie di una sfera (in questo caso, per viewDirection). Tra (quasi) due punti qualsiasi su una sfera c'è un unico grande cerchio - per esempio, fissando arbitrariamente il nostro punto "iniziale" sul polo nord, il grande cerchio sarebbe il meridiano su cui giace il punto finale. L'interpolazione da un punto all'altro si muove lungo questo grande cerchio.

Ora, per la maggior parte dei punti su una sfera, i punti vicini corrispondono ai grandi cerchi vicini; per esempio, i meridiani su cui giacciono Los Angeles e Phoenix sono abbastanza vicini l'uno all'altro. Ma quando il punto di destinazione è l' antipode del punto originale - dal polo sud al polo nord del punto iniziale - non c'è più un solo grande cerchio attraverso entrambi, ma invece tutti i grandi cerchi attraverso uno passano attraverso l'altro. Quel che è peggio, questo significa che i punti vicino al polo sud non sono "la maggior parte dei punti"; due punti vicini l'uno all'altro ed entrambi vicino al polo sud possono avere meridiani selvaggiamente divergenti.

Sospetto che ciò che vedi sia una manifestazione di questa instabilità nel meridiano - o in altre parole, l'arco di interpolazione. Quando il target del look è direttamente dietro il personaggio, allora cose come la precisione del primo ordine nella tua "integrazione di Eulero" della posizione del personaggio, e il modo in cui cambia la direzione del look frame-to-frame, li porterà selvaggiamente archi di interpolazione diversi da un fotogramma all'altro, e questo probabilmente porterà allo "sfalsamento" che stai vedendo.

Per quanto riguarda cosa farne, la cosa migliore che mi viene in mente è di non ricalcolare la direzione dello sguardo "target" in ogni fotogramma; invece, usa lo stesso per un intervallo di più fotogrammi, quindi calcola uno nuovo e usalo per più fotogrammi, ecc. Se necessario, puoi anche interpolare da un bersaglio all'altro nell'intervallo di alcuni fotogrammi in modo che la direzione del movimento non cambia troppo bruscamente.

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.