Dies ist das zweite von zwei Tutorials zur Erstellung eines „Look At“ Skripts in Unity 2022, mit dem ein Objekt auf ein anderes ausgerichtet wird.
Die Videoversion dieses Tutorials ist derzeit in dieser Sprache nicht verfügbar.
Videotranskript
Hallo zusammen!
Dies ist das zweite von zwei Tutorials zur Erstellung eines „Look At“ Skripts in Unity 2022, mit dem ein Objekt auf ein anderes ausgerichtet wird.
Im ersten Teil haben wir das Problem analysiert und eine Lösung implementiert, bei der sich das Objekt sofort dreht. In diesem Tutorial erstellen wir stattdessen eine langsamere und gleichmäßigere Rotation mit Quaternions und Slerp.
In diesem Tutorial setze ich voraus, dass ihr mit Konzepten wie Time.deltaTime und der Methode Quaternion.Slerp vertraut seid, da ich diese in anderen Tutorials behandelt habe. Falls ihr diese Themen noch nicht kennt, empfehle ich, euch zunächst diese Tutorials anzusehen.

Im vorherigen Tutorial haben wir die globalen und lokalen Achsen der Kamera besprochen, sowohl um die Achse zu bestimmen, die ihre Ausrichtung angibt, als auch um die Achse festzulegen, um die rotiert werden soll.
Anschließend haben wir das Problem auf die zweidimensionale Ebene reduziert und den Rotationswinkel berechnet, um den das 3D Modell der Surveillance Camera gedreht werden muss.
In unserem Skript heißt dieser Winkel deltaAngle und wird in Grad gemessen.
Um Slerp zu verwenden, benötigen wir drei Dinge:
das Quaternion, das die Ausgangsorientierung angibt;
das Quaternion, das die Zielorientierung angibt, die erreicht werden soll;
eine Methode, um bei jedem Frame der Spielausführung anzugeben, an welchem Punkt wir uns im Übergang von der Ausgangsorientierung zur Zielorientierung befinden, in einem Bereich von 0 bis 1.
Der erste Punkt ist der einfachste: Die Eigenschaft rotation von transform drückt die Orientierung des Objekts bereits in Form von Quaternions aus, daher verwenden wir hierfür transform.rotation.
Der zweite Punkt ist ebenfalls nicht kompliziert: Ist eine Ausgangsorientierung als Quaternion gegeben, erhält man das Quaternion der Zielorientierung, indem man die Ausgangsorientierung mit der auszuführenden Rotation multipliziert.
Die auszuführende Rotation ist in unserem Skript deltaAngle, allerdings in Grad ausgedrückt. Wir müssen diesen Wert daher als Quaternion darstellen.
Zum Glück ist die Funktion Euler der Klasse Quaternion genau dafür geeignet. Sie nimmt drei Parameter entgegen, also die Rotationswinkel um die X, Y und Z Achse, und gibt ein Quaternion zurück, das diese Transformation repräsentiert.
Wie bereits erwähnt, müssen wir das Ausgangsquaternion mit dem Rotationsquaternion multiplizieren, um das Zielquaternion zu erhalten. In Update kann ich daher schreiben:
Quaternion targetRotation = (transform.rotation * (Quaternion.Euler(0f, 0f, deltaAngle)));
Direkt danach kann ich die Orientierung des Objekts aktualisieren, indem ich das mit Quaternion.Slerp berechnete Quaternion transform.rotation zuweise:
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, evaluationTime);
Nun müssen wir natürlich evaluationTime definieren. Dabei handelt es sich um einen float Wert zwischen 0 und 1, der angibt, an welchem Punkt wir uns im Übergang von der Ausgangsorientierung zur Zielorientierung befinden.
Zunächst definiere und initialisiere ich diese Variable mit:
private float evaluationTime;
am Anfang der Skriptklasse und mit:
evaluationTime = 0f;
innerhalb der Start Methode.

Die Variable evaluationTime muss dann bei jedem Frame erhöht werden. Das kann folgendermaßen erfolgen:
evaluationTime += Time.deltaTime;
Diese Anweisung schreibe ich direkt nach der Zeile mit Slerp.
Das ist natürlich nur ein Beispiel. Ich empfehle, Time.deltaTime mit einer Variable zu multiplizieren, deren Wert im Inspector in Echtzeit angepasst werden kann, bis eine optimale Rotationsgeschwindigkeit erreicht ist. Dieses Thema habe ich in meinem Tutorial zu Time.deltaTime ausführlicher behandelt.
Auf diese Weise wird evaluationTime jedoch irgendwann den Wert 1.0 erreichen, da es bei jedem Frame erhöht wird und keine Rücksetzung erfolgt.
Aber wann sollten wir es zurücksetzen?
Anders formuliert: Wann sind wir bereit, eine neue Rotation des Modells zu starten?
Die Antwort lautet: wenn das Modell bereits auf den Player ausgerichtet ist und darauf wartet, dass er sich bewegt.
Normalerweise würde ich sagen, dass deltaAngle gleich 0 ist, wenn das Modell der Surveillance Camera auf den Player zeigt und dieser stillsteht, da keine Rotation mehr ausgeführt werden muss. Bei float Werten, insbesondere bei Umrechnungen zwischen verschiedenen Maßeinheiten, ist es jedoch sinnvoll, eine gewisse Toleranz beizubehalten. Daher definieren wir, dass die Animation beendet ist und eine neue starten kann, sobald sich der Player wieder bewegt, wenn der Absolutwert von deltaAngle kleiner als 1f ist.
Direkt vor der Erstellung von targetRotation, innerhalb der Update Methode, schreibe ich daher:
if(Mathf.Abs(deltaAngle) < 1f) evaluationTime = 0f;
Anschließend verschiebe ich die drei folgenden Anweisungen, also die Definition des Zielquaternions, die Orientierungsänderung mit Slerp und die Erhöhung von evaluationTime, in den else Block dieser if Anweisung.

Ich speichere das geänderte Skript, kehre in den Unity Editor zurück und drücke Play, um das Ergebnis zu beobachten. In diesem Fall wird die Rotationsgeschwindigkeit ausschließlich durch Time.deltaTime bestimmt und kann, wie zuvor erwähnt, durch Multiplikation mit einer interaktiv einstellbaren Variable verringert oder erhöht werden.

Zusammenfassend haben wir in diesem Tutorial gesehen, wie man den Rotationswinkel in Quaternions umwandelt, um das Quaternion der Zielorientierung zu berechnen. Anschließend haben wir Slerp verwendet, um langsamere Rotationen durchzuführen, deren Geschwindigkeit mithilfe von Time.deltaTime plattformunabhängig kalibriert werden kann.
Außerdem haben wir eine Reset Bedingung für Slerp definiert, sodass die Rotation neu startet, wenn der Player stillsteht und bereit ist, sich erneut zu bewegen.
Damit sind wir am Ende dieser beiden Tutorials angekommen. Bis bald!