Moltiplicazione
Almeno in termini di implementazione dei Quaternioni da parte di Unity, l'ordine di moltiplicazione descritto nella domanda non è corretto. Questo è importante perché la rotazione 3D non è commutativa .
Quindi, se voglio ruotare un oggetto rotationChange
partendo dal suo, currentOrientation
lo scriverei in questo modo:
Quaternion newOrientation = rotationChange * currentOrientation;
(ad es. le trasformazioni si accumulano verso sinistra - lo stesso della convenzione di matrice di Unity. La rotazione più a destra viene applicata prima / all'estremità "più locale")
E se volessi trasformare una direzione o un offset vettore con una rotazione, lo scriverei in questo modo:
Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;
(Unity genererà un errore di compilazione se si fa il contrario)
mescolanza
Nella maggior parte dei casi puoi cavartela con le rotazioni di Lerping. Questo perché l'angolo usato "sotto il cofano" in un quaternione è metà dell'angolo di rotazione, rendendolo sostanzialmente più vicino all'approssimazione lineare di Lerp rispetto a qualcosa come una Matrix (che in generale non Lerp bene!). Guarda circa 40 minuti in questo video per ulteriori spiegazioni .
L'unico caso in cui hai davvero bisogno di Slerp è quando hai bisogno di una velocità costante nel tempo, come l'interpolazione tra i fotogrammi chiave su una sequenza temporale di animazione. Per i casi in cui ti interessa solo che un'uscita sia intermedia tra due ingressi (come la fusione di livelli di un'animazione), di solito Lerp serve abbastanza bene.
Cos'altro?
Il prodotto punto di due quaternioni unità fornisce il coseno dell'angolo tra di loro, quindi è possibile utilizzare il prodotto punto come misura di somiglianza se è necessario confrontare le rotazioni. Questo è un po 'oscuro, quindi per codice più leggibile userei spesso Quaternion.Angle (a, b) , che invece esprime più chiaramente che stiamo confrontando gli angoli, in unità familiari (gradi).
Questi tipi di metodi di convenienza forniti da Unity per i Quaternioni sono super utili. In quasi tutti i progetti ne uso almeno uno alcune volte :
Quaternion.LookRotation(Vector3 forward, Vector3 up)
Questo crea un quaternione che:
- ruota l'asse z + locale per puntare esattamente lungo l'
forward
argomento vettoriale
- ruota l'asse y + locale per puntare il più vicino possibile
up
all'argomento vettoriale, se fornito, o (0, 1, 0)
se omesso
Il motivo per cui "su" diventa "il più vicino possibile" è che il sistema è troppo determinato. Affrontare z + per forward
utilizzare fino a due gradi di libertà (ad es. Imbardata e beccheggio), quindi rimane solo un grado di libertà (rollio).
Trovo abbastanza spesso che voglio qualcosa con le proprietà di esattezza opposte: voglio che y + locale punti esattamente lungo up
, e z + locale si avvicini il più possibile alla forward
libertà rimanente.
Questo viene ad esempio quando provo a formare un riquadro di coordinate relativo alla telecamera per l'input di movimento: voglio che la mia direzione verso l'alto locale rimanga perpendicolare al pavimento o alla superficie inclinata normale, quindi il mio input non tenta di scavare il personaggio nel terreno o levitarli fuori di esso.
Potresti anche ottenere questo se vuoi che l'alloggiamento della torretta di un carro armato sia rivolto verso un bersaglio, senza staccarsi dal corpo del carro armato quando miri su / giù.
Possiamo realizzare la nostra funzione di convenienza per farlo, usando LookRotation
per il sollevamento pesante:
Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);
return rotateZToUp * rotateYToZ;
}
Qui prima ruotiamo y + locale su + z, e z + locale su y-.
Quindi ruotiamo il nuovo z + nella nostra direzione verso l'alto (quindi il risultato netto è y + locale direttamente lungo exactUp
) e il nuovo y + il più vicino possibile alla direzione in avanti negata (quindi il risultato netto è z + punti locale il più vicino possibile lungo lungo approximateForward
)
Un altro pratico metodo di praticità è Quaternion.RotateTowards
, che uso spesso così:
Quaternion newRotation = Quaternion.RotateTowards(
oldRotation,
targetRotation,
maxDegreesPerSecond * Time.deltaTime
);
Questo ci consente di avvicinarci targetRotation
a una velocità costante e controllabile indipendentemente dal framerate, importante per le rotazioni che influenzano il risultato / la correttezza delle meccaniche di gioco (come girare il movimento di un personaggio o avere una torretta da rintracciare sul giocatore). Lerping / Slerping ingenui in questa situazione possono facilmente portare a casi in cui il movimento diventa più scattante ad alti framerate, influenzando l'equilibrio del gioco. (Questo non vuol dire che questi metodi sono sbagliati: ci sono modi per usarli correttamente senza cambiare equità, richiede solo cura. RotateTowards
Fornisce una scorciatoia conveniente che si prende cura di questo per noi)
n
orientamenti diversi (atteggiamenti, pose, ecc.). Quindi puoi mediarli usando i pesi, generalizzando efficacemente slerp / lerp. Puoi anche convertire un quaternione in un rotore, il che equivale ad applicare una velocità angolare per un certo periodo di tempo a un corpo rigido. Quindi puoi descrivere l'integrazione della velocità angolare anche con i quaternioni. Puoi anche stimare quanto siano diversi i due orientamenti (calcola la lunghezza dell'arco attraversato dai due quaternioni nell'ipersfera).