Saya memutar karakter permainan saya untuk menonton di target menggunakan kode berikut:
transform.rotation = Quaternion.Slerp(startQuaternion, lookQuaternion, turningNormalizer*turningSpeed/10f)
startQuaternion adalah rotasi karakter saat ini ketika target baru diberikan.
lookQuaternion adalah arah karakter yang harus dilihat dan diatur seperti ini:
destinationVector = currentWaypoint.transform.position - transform.position;
lookQuaternion = Quaternion.LookRotation(destinationVector, Vector3.up);
turningNormalizer baru saja Time.deltaTime
bertambah dan turningSpeed
merupakan nilai statis yang diberikan dalam editor.
Masalahnya adalah bahwa sementara karakter berubah sebagaimana mestinya sebagian besar waktu, ia memiliki masalah ketika harus melakukan hampir 180 derajat. Maka kadang-kadang kegugupan dan mencerminkan rotasi:
Dalam gambar yang digambar dengan buruk ini, karakter (di kanan) mulai berbelok ke arah lingkaran di sebelah kiri. Alih-alih hanya memutar baik melalui kiri atau kanan itu memulai "tarian cermin" ini:
- Itu mulai berputar ke arah menghadap baru
- Kemudian tiba-tiba terkunci ke sudut yang sama tetapi di sisi lain dan terus berputar
Itu melakukan "mirroring" begitu lama sampai terlihat pada target. Apakah ini hal dengan angka empat, slerping / lerping atau sesuatu yang lain?
EDIT1: Rupanya masalah tidak muncul dari rotasi itu sendiri. Masalah yang lebih mungkin adalah bahwa karakter bergerak ke arah menghadap sementara itu berputar. Seperti membatasi sudut, antara menghadap dan target, ketika karakter dibiarkan bergerak mengurangi dan kadang-kadang menghilangkan rotasi jittering / mirroring.
Ini tentu saja menimbulkan lebih banyak pertanyaan, mengapa karakter tidak dapat bergerak dan berputar pada saat yang sama tanpa masalah? Kode yang digunakan untuk perpindahan:
transform.Translate(Vector3.forward * runningSpeed/10f * Time.deltaTime);
Jawaban:
Setiap orientasi dalam ruang 3D dapat diwakili oleh 2 angka kuat unit yang berbeda,
q
dan-q
(komponen dinegasikanq
). Misalnya orientasi yang diwakili oleh matriks identitas 3x3I
dapat diwakili oleh 2 angka empat:Keduanya mewakili orientasi yang sama dalam ruang 3D, produk titik mereka persis
-1
, masing-masing terletak di belahan bumi lain, persis di sisi berlawanan dari hypersphere.Hasil yang Anda amati ketika slerp membutuhkan busur yang lebih panjang untuk berputar, adalah ketika slerping antara 2 angka empat yang tidak terletak di belahan bumi yang sama. Jika itu terjadi, cukup singkirkan salah satu dari mereka sebelum slerping mereka, maka slerp akan mengambil busur yang lebih pendek.
Produk titik adalah alat yang mudah untuk mengetahui apakah itu terjadi. Jika produk titik dari kedua angka empat kurang dari
0
, maka mereka tidak terletak di belahan bumi yang sama. Jadi jika produk titik keduanya kurang dari0
, hanya komponen-bijaksana meniadakan angka empat lainnya sebelum slerping mereka.sumber
if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Inverse(startQuaternion); }
tetapi itu tidak memperbaiki masalah. Maaf untuk pemformatan yang buruk, sepertinya saya tidak bisa menjinakkan bagian komentar ini.Inverse
, itu operasi yang berbeda dariNegate
.if(Quaternion.Dot (lookQuaternion, q) < 0) { q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w; }
Saya tidak menggunakan C #, tetapi dari tampilan dokumen, sepertinya Anda juga bisa menggunakan Fungsi-Negasi secara langsung.if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Negate(startQuaternion); }
Nah masalah Anda adalah karena kedua vektor yang membentuk angka empat Anda membuat 180 derajat, jadi pertanyaan yang harus ditanyakan ketika interpolasi busur mana yang seharusnya diambil? busur atas atau yang lebih rendah ??
Inilah yang pada dasarnya menyebabkan mirroring, setiap kali Anda menginterpolasinya mengambil arah sebaliknya sambil tetap mempertahankan sudutnya.
Menurut tautan ini .
Yang perlu Anda lakukan adalah menginterpolasi angka awal Anda dengan angka empat menengah (untuk menentukan busur mana yang akan diambil) dan ketika tercapai gunakan angka empat menengah untuk melanjutkan ke angka empat target yang sebenarnya.
sumber
Masalah yang saya duga Anda lihat tidak ada hubungannya dengan kode Anda, tetapi lebih merupakan masalah mendasar dengan interpolasi di sepanjang permukaan bola (dalam hal ini, untuk viewDirection). Di antara (hampir) dua titik pada sebuah bola ada satu lingkaran besar - misalnya, secara sewenang-wenang memperbaiki titik 'awal' kami di kutub utara, lingkaran besar itu akan menjadi meridian tempat titik akhir berada. Interpolasi dari satu titik ke titik lainnya bergerak di sepanjang lingkaran besar ini.
Sekarang, untuk sebagian besar titik di bola, titik terdekat sesuai dengan lingkaran besar terdekat; misalnya, garis bujur yang dimiliki Los Angeles dan Phoenix cukup dekat satu sama lain. Tetapi ketika titik tujuan adalah antipode dari titik asli - kutub selatan ke kutub utara titik awal - tidak ada lagi lingkaran besar melalui keduanya, tetapi semua lingkaran besar melalui satu melewati yang lain. Yang lebih buruk, ini berarti bahwa titik-titik di dekat kutub selatan bukan 'titik terbanyak'; dua titik saling berdekatan dan keduanya di dekat kutub selatan dapat memiliki meridian yang sangat berbeda.
Saya menduga apa yang Anda lihat adalah manifestasi dari ketidakstabilan ini di meridian - atau dengan kata lain, busur interpolasi. Ketika target tampilan berada tepat di belakang karakter, maka hal-hal seperti ketidaktepatan urutan pertama dalam 'integrasi Euler' Anda dari posisi karakter, dan cara yang mengubah arah tampilan frame-to-frame, akan mengarah ke ini secara liar busur interpolasi berbeda dari satu frame ke yang berikutnya, dan ini kemungkinan akan menyebabkan 'sempoyongan' yang Anda lihat.
Sejauh apa yang harus dilakukan dengan itu, hal terbaik yang muncul dalam pikiran adalah untuk tidak menghitung ulang arah pandangan 'target' setiap frame; alih-alih, gunakan yang sama untuk rentang beberapa frame, lalu hitung yang baru dan gunakan untuk beberapa frame, dll. Jika perlu, Anda bahkan dapat menginterpolasi dari satu target ke target berikutnya selama rentang beberapa frame sehingga arah gerakan tidak berubah terlalu tiba-tiba.
sumber