Perkalian
Paling tidak dalam hal implementasi Quaternions dari Unity, urutan multiplikasi yang dijelaskan dalam pertanyaan itu tidak benar. Ini penting karena rotasi 3D tidak komutatif .
Jadi, jika saya ingin memutar objek dengan rotationChange
memulainya, currentOrientation
saya akan menulisnya seperti ini:
Quaternion newOrientation = rotationChange * currentOrientation;
(mis. Transformasi menumpuk ke kiri - sama dengan konvensi matriks Unity. Rotasi paling kanan diterapkan pertama / pada ujung "paling lokal")
Dan jika saya ingin mengubah arah atau mengimbangi vektor dengan rotasi, saya akan menulis seperti ini:
Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;
(Unity akan menghasilkan kesalahan kompilasi jika Anda melakukan yang sebaliknya)
Memadukan
Untuk sebagian besar kasus, Anda dapat menggunakan rotasi Lerping. Itu karena sudut yang digunakan "di bawah tenda" dalam angka empat adalah setengah sudut rotasi, membuatnya jauh lebih dekat dengan perkiraan linier Lerp daripada sesuatu seperti Matriks (yang secara umum tidak akan Lerp dengan baik!). Lihat sekitar 40 menit dalam video ini untuk penjelasan lebih lanjut .
Satu-satunya kasus ketika Anda benar-benar membutuhkan Slerp adalah ketika Anda membutuhkan kecepatan yang konsisten dari waktu ke waktu, seperti menginterpolasi antar kerangka kunci pada timeline animasi. Untuk kasus-kasus di mana Anda hanya peduli bahwa output adalah perantara antara dua input (seperti memadukan lapisan animasi) maka biasanya Lerp berfungsi dengan cukup baik.
Apa lagi?
Produk titik dari dua unit angka empat memberikan cosinus sudut di antara mereka, sehingga Anda dapat menggunakan produk titik sebagai ukuran kesamaan jika Anda perlu membandingkan rotasi. Ini sedikit tidak jelas, jadi untuk kode yang lebih mudah dibaca, saya sering menggunakan Quaternion.Angle (a, b) sebagai gantinya, yang lebih jelas menyatakan bahwa kami membandingkan sudut, dalam satuan yang dikenal (derajat).
Jenis metode kenyamanan yang disediakan Unity untuk Quaternions sangat berguna. Di hampir setiap proyek saya menggunakan yang ini setidaknya beberapa kali :
Quaternion.LookRotation(Vector3 forward, Vector3 up)
Ini membangun angka empat yang:
- memutar sumbu z + lokal untuk menunjuk tepat di sepanjang
forward
argumen vektor
- memutar sumbu y + lokal ke titik sedekat mungkin dengan
up
argumen vektor, jika disediakan, atau ke (0, 1, 0)
jika dihilangkan
Alasan "naik" hanya "sedekat mungkin" adalah karena sistemnya terlalu ditentukan. Menghadapi z + untuk forward
menggunakan dua derajat kebebasan (mis. Yaw dan pitch) sehingga kita hanya memiliki satu derajat kebebasan tersisa (roll).
Saya menemukan cukup sering saya menginginkan sesuatu dengan sifat ketepatan yang berlawanan: Saya ingin y + lokal untuk menunjukkan tepat bersama up
, dan z + lokal untuk sedekat mungkin forward
dengan kebebasan yang tersisa.
Ini muncul misalnya ketika mencoba untuk membentuk kerangka koordinat relatif kamera untuk input gerakan: Saya ingin arah naik lokal saya tetap tegak lurus dengan lantai atau permukaan yang cenderung normal, jadi input saya tidak mencoba untuk memasukkan karakter ke medan. atau mengangkat mereka dari itu.
Anda juga bisa mendapatkan ini jika Anda ingin rumah menara dari sebuah tank untuk menghadapi target, tanpa terkelupas dari tubuh tangki ketika membidik atas / bawah.
Kita dapat membangun fungsi kenyamanan kita sendiri untuk melakukan ini, menggunakan LookRotation
untuk mengangkat berat:
Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);
return rotateZToUp * rotateYToZ;
}
Di sini kita pertama-tama memutar lokal y + ke z +, dan lokal z + ke y-.
Kemudian kami memutar z + baru ke arah atas kami (jadi hasil bersihnya adalah titik lokal y + langsung di sepanjang exactUp
), dan y + baru sedekat mungkin dengan arah maju yang dinegasikan (jadi hasil bersihnya adalah titik z + lokal sedekat mungkin sepanjang approximateForward
)
Metode kenyamanan praktis lainnya adalah Quaternion.RotateTowards
, yang sering saya gunakan seperti ini:
Quaternion newRotation = Quaternion.RotateTowards(
oldRotation,
targetRotation,
maxDegreesPerSecond * Time.deltaTime
);
Ini memungkinkan kita mendekat pada targetRotation
kecepatan yang konsisten dan terkendali terlepas dari framerate - penting untuk rotasi yang mempengaruhi hasil / keadilan mekanisme permainan (seperti memutar gerakan karakter, atau memiliki track-in turret pada pemain). Lerping / Slerping secara naif dalam situasi ini dapat dengan mudah menyebabkan kasus di mana gerakan menjadi lebih cepat pada framerate tinggi, yang berdampak pada keseimbangan game. (Itu tidak berarti metode ini salah - ada cara untuk menggunakannya dengan benar tanpa mengubah keadilan, itu hanya membutuhkan perawatan. RotateTowards
Memberikan jalan pintas yang nyaman yang menangani ini untuk kita)
n
orientasi yang berbeda (sikap, pose, dll). Kemudian Anda dapat rata-rata menggunakan bobot, secara efektif menggeneralisasi slerp / lerp. Anda juga dapat mengubah angka empat menjadi rotor, yang setara dengan menerapkan kecepatan sudut untuk jumlah waktu tertentu ke benda tegar. Karenanya Anda dapat menggambarkan integrasi kecepatan sudut dengan angka empat juga. Anda juga dapat memperkirakan seberapa berbeda dua orientasi itu (menghitung panjang busur yang direntang oleh dua angka empat pada hypersphere).