In diesem Tutorial werden wir die Funktion Slerp von Quaternion in Unity untersuchen, die es uns ermöglicht, von einer Anfangsorientierung zu einer Endorientierung über einen bestimmten Zeitraum zu wechseln und dabei weiche Rotationen auszuführen.
Die Videoversion dieses Tutorials ist derzeit in dieser Sprache nicht verfügbar.
Videotranskript
Hallo zusammen!
In diesem Tutorial werden wir die Funktion Slerp von Quaternion in Unity untersuchen, die es uns ermöglicht, von einer Anfangsorientierung zu einer Endorientierung über einen bestimmten Zeitraum zu wechseln und dabei weiche Rotationen auszuführen.
In diesem Tutorial setze ich voraus, dass du bereits mit Time.deltaTime vertraut bist, das ich in einem zuvor veröffentlichten Videotutorial behandelt habe. Falls dir Time.deltaTime nicht vertraut ist, empfehle ich dir dringend, dieses Video anzusehen, bevor du mit diesem fortfährst.
Dieses Tutorial wurde mit Unity 2022 aufgenommen. Die Funktion Slerp ist jedoch in mehreren Versionen verfügbar und wird voraussichtlich auch in zukünftigen Versionen vorhanden sein.
Eine Rotation von Orientierung A zu Orientierung B, oder allgemeiner eine Interpolation zwischen Wert A und Wert B über einen bestimmten Zeitraum, kann auf verschiedene Arten erfolgen: Die Werte können einer linearen Progression, einer sphärischen Progression oder anderen Arten von Progressionen folgen, einschließlich benutzerdefinierter Varianten.
Im Video zeige ich einige Beispiele für Interpolation, konkret die Rotation eines Würfels um 90 Grad um seine vertikale Achse. Es ist ein einfaches Beispiel, vermittelt aber das Konzept sehr anschaulich.
Die Rotationszeit wird im Bereich [0,1] abgebildet. Zum Zeitpunkt 0 haben wir den Anfangswert und zum Zeitpunkt 1 den Endwert. Zwischenwerte innerhalb dieses Bereichs entsprechen den durch die gewählte Interpolation bestimmten Werten.
In den Beispielen rotieren die Würfel alle um 90 Grad in 5 Sekunden. In der vierten Sekunde der Animation, was dem Zeitpunkt 0.8 im Bereich [0,1] entspricht, haben die verschiedenen Würfel jedoch unterschiedliche Orientierungen, da ihre Interpolationen unterschiedlich sind.

Bei Rotationen wie in unserem Fall ist die sphärische Interpolation der linearen Interpolation vorzuziehen, da das Ergebnis angenehmer wirkt.
In Unity wird die sphärische Interpolation mit der Funktion Slerp berechnet, wobei das S für Spherical steht. Die lineare Interpolation wird mit der Funktion Lerp berechnet, wobei das L für Linear steht.
Wie bereits erwähnt, ist Slerp Teil der Quaternion Klasse, mit der Orientierungen und Rotationen im 3D Raum mithilfe von Quaternionen definiert werden können. Dabei handelt es sich um ein mathematisches Konzept, das ich in diesem Tutorial nicht erklären werde.
Ich beschränke mich darauf zu sagen, dass sie zur Darstellung von Orientierungen verwendet werden und hoffe, dass mir die Mathematiker diese Vereinfachung verzeihen. Stattdessen zeige ich dir, wie die Funktion Slerp verwendet wird.
Slerp wird verwendet, um von Orientierung A zu Orientierung B zu wechseln.
Sie nimmt drei Parameter entgegen: die Anfangsorientierung, die Zielorientierung und den Zeitpunkt im Bereich [0,1], zu dem wir die Orientierung ermitteln möchten, also den Zeitpunkt, an dem wir die Interpolation auswerten wollen.
Slerp gibt ein Quaternion zurück, das die zum angegebenen Zeitpunkt ausgewertete Orientierung repräsentiert.
Wenn wir also schreiben:
Quaternion.Slerp(A, B, 0.2);
fordern wir Unity auf, die Orientierung zu berechnen, die das Objekt bei einem Fünftel der Rotation von Orientierung A zu Orientierung B haben muss, da 0.2 einem Fünftel von 1 entspricht.
Wenn die Animation 1 Sekunde dauern soll, können wir Time.deltaTime in Update verwenden, da der Interpolationsbereich von 0 bis 1 mithilfe von Time.deltaTime in Update perfekt in eine einsekündige Animation umgewandelt werden kann, wie ich im Videotutorial zu Time.deltaTime gezeigt habe.
Wenn die Animation hingegen eine beliebige Anzahl von Sekunden dauern soll, müssen wir Time.deltaTime durch diese Anzahl teilen. Darauf gehe ich gleich anhand eines praktischen Beispiels näher ein.
Meistens ist die Anfangsorientierung die Orientierung des Objekts, also transform.rotation, da Rotationen als Quaternionen ausgedrückt werden.
Die Zielorientierung zu berechnen, zum Beispiel indem man einen Winkel in Grad zur Anfangsorientierung hinzufügt, kann problematisch sein. Auch das werden wir gleich im praktischen Beispiel behandeln. Nun kommen wir endlich zu einem konkreten Beispiel.
Im Video zeige ich eine Szene mit einem 3D Modell.

Genauer gesagt besteht das Modell aus vier Elementen: dem Türrahmen, den zwei Türflügeln und einem Griff.
Obwohl sich der Pivot Punkt des Türflügels mit dem Griff in meinem ursprünglichen Modell an den Scharnieren befand und die Rotation korrekt ermöglichte, hat Unity ihn aus irgendeinem Grund etwas nach vorne verschoben.
Um dieses Problem zu lösen, füge ich dem Rahmen ein Empty Objekt als Child hinzu und positioniere es an einem der Scharniere des Türflügels, den ich animieren möchte.
Anschließend mache ich den Türflügel zum Child dieses Empty.
Dieses neue Empty Objekt benötigt ein Rotationsskript, das wir sofort erstellen und zum Beispiel doorOpening nennen.
Konkret soll sich der Türflügel zu Beginn des Spiels automatisch öffnen und sich um 90 Grad um seine lokale vertikale Achse drehen, die in diesem Fall die Z Achse ist.

Die Anfangsorientierung ist transform.rotation.
Der Einfachheit halber und um den Code flexibler zu machen, deklariere ich außerdem eine Quaternion Variable mit dem Namen startRotation und initialisiere sie in Start mit:
startRotation = transform.rotation;
Das Quaternion, das die Endorientierung repräsentiert, muss der Anfangsorientierung plus einer Rotation von 90 Grad um die lokale Z Achse entsprechen. Doch wie definieren wir diese Rotation als Quaternion?
Hier hilft uns die Funktion Quaternion.Euler, die drei Parameter entgegennimmt: die Rotationswinkel in Grad um die drei Achsen X, Y und Z.
Wir definieren also das Quaternion der auszuführenden Rotation als:
Quaternion rotationToBePerformed;
und initialisieren es in Start mit:
rotationToBePerformed = Quaternion.Euler(0f, 0f, 90f);
Dieses Quaternion repräsentiert die auszuführende Operation, ist jedoch noch nicht die Endorientierung.
Diese müssen wir berechnen, indem wir diesen Wert zur Anfangsorientierung hinzufügen.
Und hier kommt der entscheidende Punkt: Um die auszuführende Rotation zur Anfangsorientierung hinzuzufügen, müssen die beiden Quaternionen miteinander MULTIPLIZIERT werden.
Wir definieren also das Ziel Quaternion als:
Quaternion targetRotation;
und initialisieren es in Start mit:
targetRotation = startRotation * rotationToBePerformed;
Wechseln wir nun in die Update Funktion, die bei jedem Frame des Spiels aufgerufen wird, und schreiben:
transform.rotation = Quaternion.Slerp(startRotation, targetRotation
Hier stoppen wir, denn wir haben noch keine Variable für den Auswertungszeitpunkt der Interpolation definiert.
Diese Variable muss bei 0 beginnen. Daher definieren und initialisieren wir sie außerhalb von Update mit:
float evaluation = 0f;
Dann können wir sie auch als dritten Parameter an die Funktion Quaternion.Slerp übergeben.
Da ihr Wert in jedem Frame steigen muss, schreiben wir in Update:
evaluation += Time.deltaTime;

Wir wissen, dass der finale Auswertungszeitpunkt 1.0 sein wird. Daher dauert diese Animation genau eine Sekunde, da wir evaluation in jedem Frame um Time.deltaTime erhöhen.
Beim Start des Spiels werden wir feststellen, dass sich das Empty um seine vertikale Achse dreht, sich der Türflügel jedoch nicht öffnet.
Das liegt daran, dass ich dieses Objekt ursprünglich als Static markiert hatte, da ich nicht vorhatte, es zu animieren, und Unity die globale Beleuchtung berechnen sollte. Jetzt möchte ich es jedoch animieren, daher deaktiviere ich das Kontrollkästchen Static im Inspector und bestätige die Änderung auch für die Child Objekte, also zum Beispiel den Griff.
Starten wir das Spiel erneut, sehen wir diesmal, wie sich die Tür innerhalb einer Sekunde mit weicher Interpolation öffnet.

Wie können wir nun eine andere Animationsdauer festlegen?
Die Antwort ist einfach: Die Erhöhung von evaluation in jedem Frame muss Time.deltaTime geteilt durch die Animationsdauer entsprechen.
Mit nur Time.deltaTime dauert die Animation eine Sekunde. Um sie zum Beispiel 5 Sekunden dauern zu lassen, müssen wir evaluation in jedem Frame nur um ein Fünftel von Time.deltaTime erhöhen.
Definieren wir also eine Variable:
float openingDuration = 5f;
Da die Animation 5 Sekunden dauern soll, ändern wir die Anweisung zur Aktualisierung von evaluation in der Update Methode wie folgt:
evaluation += (Time.deltaTime / openingDuration);

Speichere das Skript, kehre in den Unity Editor zurück und starte das Spiel, um das Ergebnis zu sehen. Dieses Mal dauert die Animation 5 Sekunden.
Mit diesem praktischen Beispiel hast du gesehen, wie man Quaternion.Slerp verwendet, um zwischen zwei Orientierungen über eine bestimmte Dauer weich zu interpolieren.
Du kannst dieses Skript an verschiedene Szenarien oder Objekte anpassen, um in deinen Unity Projekten weiche Rotationen und Animationen zu erzielen.
Fassen wir zusammen: In diesem Tutorial haben wir behandelt, wie man die auszuführende Rotation als Quaternion ausdrückt, wie man das Ziel Quaternion erhält, indem man das Start Quaternion mit der auszuführenden Rotation multipliziert, und wie man die Funktion Slerp verwendet, um Rotationen mit sphärischer Interpolation auszuführen, mit variabler Dauer und konstanter Ausführungsgeschwindigkeit unabhängig von der Framerate dank Time.deltaTime.
Ich hoffe, dieses Tutorial war hilfreich für dich. Bis bald!