Nie, to nie jest błąd silnika lub artefakt określonej reprezentacji obrotu (mogą się one również zdarzyć, ale ten efekt dotyczy każdego systemu, który reprezentuje obroty, włącznie z czwartorzędami).
Odkryłeś prawdziwy fakt na temat działania rotacji w przestrzeni trójwymiarowej i odbiega ona od naszej intuicji dotyczącej innych transformacji, takich jak tłumaczenie:
Kiedy tworzymy rotacje na więcej niż jednej osi, otrzymujemy wynik nie tylko całkowitą / netto wartość, którą zastosowaliśmy do każdej osi (jak można się spodziewać w tłumaczeniu). Kolejność, w jakiej stosujemy obroty, zmienia wynik, ponieważ każdy obrót przesuwa osie, na których stosowane są następne obroty (jeśli obraca się wokół lokalnych osi obiektu) lub relację między obiektem a osią (jeśli obraca się wokół świata osie).
Zmiana relacji osi w czasie może mylić naszą intuicję co do tego, co każda z osi ma „robić”. W szczególności niektóre kombinacje obrotu w odchyleniu i skoku dają taki sam wynik, jak w przypadku obrotu!
Możesz sprawdzić, czy każdy krok obraca się prawidłowo wokół żądanej osi - nie ma usterki silnika ani artefaktu w naszym zapisie, który koliduje z naszym wejściem lub zgaduje go z drugiej strony - sferyczny (lub nadprzestrzenny / czwartorzędowy) obrót oznacza po prostu nasze zawijanie transformacji wokół siebie. Mogą być lokalnie ortogonalne, dla małych rotacji, ale gdy się gromadzą, okazuje się, że nie są globalnie ortogonalne.
Jest to najbardziej dramatyczne i wyraźne dla zakrętów o 90 stopni, jak te powyżej, ale osie wędrujące pełzają również przy wielu małych obrotach, jak pokazano w pytaniu.
Co więc z tym zrobimy?
Jeśli masz już system obrotu z odchyleniem skoku, jednym z najszybszych sposobów wyeliminowania niepożądanego przechylenia jest zmiana jednego z obrotów, aby działał na globalnej lub macierzystej osi transformacji zamiast na lokalnych osiach obiektu. W ten sposób nie można uzyskać zanieczyszczenia krzyżowego między nimi - jedna oś pozostaje całkowicie kontrolowana.
Oto ta sama sekwencja pitch-yaw-pitch, która stała się rzutem w powyższym przykładzie, ale teraz stosujemy nasze odchylenie wokół globalnej osi Y zamiast obiektu
Możemy więc naprawić kamerę pierwszoosobową za pomocą mantry „Pitch Locally, Yaw Global”:
void Update() {
float speed = lookSpeed * Time.deltaTime;
transform.Rotate(0f, Input.GetAxis("Horizontal") * speed, 0f, Space.World);
transform.Rotate(-Input.GetAxis("Vertical") * speed, 0f, 0f, Space.Self);
}
Jeśli sumujesz rotacje za pomocą mnożenia, odwróć lewą / prawą kolejność jednego z mnożeń, aby uzyskać ten sam efekt:
// Yaw happens "over" the current rotation, in global coordinates.
Quaternion yaw = Quaternion.Euler(0f, Input.GetAxis("Horizontal") * speed, 0f);
transform.rotation = yaw * transform.rotation; // yaw on the left.
// Pitch happens "under" the current rotation, in local coordinates.
Quaternion pitch = Quaternion.Euler(-Input.GetAxis("Vertical") * speed, 0f, 0f);
transform.rotation = transform.rotation * pitch; // pitch on the right.
(Konkretna kolejność będzie zależeć od konwencji mnożenia w twoim środowisku, ale lewy = więcej globalny / prawy = więcej lokalny jest częstym wyborem)
Jest to równoważne z zapamiętywaniem całkowitego odchylenia netto i skoku całkowitego, który chcesz jako zmienne zmiennoprzecinkowe, a następnie zawsze stosowanie wyniku netto naraz, konstruowanie pojedynczej czwartorzędowej orientacji czwartorzędowej lub macierzy z tych samych kątów (pod warunkiem, że trzymasz się totalPitch
zaciśniętego):
// Construct a new orientation quaternion or matrix from Euler/Tait-Bryan angles.
var newRotation = Quaternion.Euler(totalPitch, totalYaw, 0f);
// Apply it to our object.
transform.rotation = newRotation;
lub równoważnie ...
// Form a view vector using total pitch & yaw as spherical coordinates.
Vector3 forward = new Vector3(
Mathf.cos(totalPitch) * Mathf.sin(totalYaw),
Mathf.sin(totalPitch),
Mathf.cos(totalPitch) * Mathf.cos(totalYaw));
// Construct an orientation or view matrix pointing in that direction.
var newRotation = Quaternion.LookRotation(forward, new Vector3(0, 1, 0));
// Apply it to our object.
transform.rotation = newRotation;
Korzystając z tego podziału globalnego / lokalnego, obroty nie mają szansy na łączenie się i wpływanie na siebie, ponieważ są stosowane do niezależnych zestawów osi.
Ten sam pomysł może pomóc, jeśli jest to obiekt na świecie, który chcemy obrócić. Na przykład taki jak kula ziemska, często chcielibyśmy go odwrócić i zastosować nasze odchylenie lokalnie (dzięki czemu zawsze obraca się wokół biegunów) i przechylać się globalnie (więc przechyla się w kierunku / z dala od naszego widoku, a nie w kierunku / z dala od Australii , gdziekolwiek wskazuje ...)
Ograniczenia
Ta globalna / lokalna strategia hybrydowa nie zawsze jest właściwym rozwiązaniem. Na przykład w grze z lotem / pływaniem 3D możesz chcieć być skierowany prosto w górę / prosto w dół i nadal mieć pełną kontrolę. Ale dzięki tej konfiguracji uderzysz w blokadę gimbala - twoja oś odchylenia (globalne w górę) staje się równoległa do osi przechyłu (lokalny do przodu) i nie możesz spojrzeć w lewo ani w prawo bez skręcania.
Zamiast tego w takich przypadkach możesz użyć czystych lokalnych rotacji, tak jak to rozpoczęliśmy w powyższym pytaniu (aby twoje kontrolki czuły to samo bez względu na to, gdzie patrzysz), co początkowo pozwoli, aby trochę się wkradło - ale potem poprawiamy to.
Na przykład, możemy użyć obrotów lokalnych, aby zaktualizować nasz wektor „do przodu”, a następnie użyć tego wektora do przodu wraz z referencyjnym wektorem „do góry”, aby skonstruować naszą ostateczną orientację. (Używając na przykład metody Quitynion.LookRotation firmy Unity lub ręcznie konstruując macierz ortonormalną z tych wektorów). Kontrolując wektor w górę, kontrolujemy rolkę lub skręcenie.
Na przykład w locie / pływaniu będziesz chciał stopniowo stosować te poprawki. Jeśli jest to zbyt gwałtowne, widok może się rozpraszać. Zamiast tego możesz użyć obecnego wektora w górę odtwarzacza i podpowiedzieć go w kierunku pionowym, klatka po klatce, aż jego poziom wyrówna się. Stosowanie tego podczas tury może czasami być mniej mdłości niż skręcanie kamery, gdy elementy sterujące odtwarzacza są bezczynne.