Cara Membuat Rotasi yang Halus Menggunakan Quaternion
Pada tulisan sebelumnya saya sudah memperlihatkan bagaimana saya merotasi sebuah objek menggunakan quaternion. Dan pada kesempatan kali ini saya akan memperilhatkan kekurangan dari cara merotasi objek saya sebelumnya dan bagaimana cara untuk menangani kekurangan tersebut.
Kekurangan dari cara sebelumnya adalah dikarenakan cara yang digunakan dibuat sesimpel mungkin sehingga menghilangkan beberapa step/langkah dalam melakukan perotasian objek. Coba perhatikan pergerakan objek dibawah, apabila objek mendadak memutar balik ke balakang, maka rotasi nampak kasar atau memutar secara tiba-tiba seperti ini:
Lalu bagaimana seharusnya yang lebih baik? Teman-teman bisa melihat contohnya dari game Dota 2 yang rotasi nya halus, professional, dan contohnya mudah teman-teman temui sendiri. Dan kemudian teman-teman bisa menyimak tulisan ini untuk mengetahui bagaimana dengan meng-implementasikan Spherical Linear Interpolation (SLERP), dapat menghasilkan rotasi yang halus seperti ini:
Bagaimana, terlihat halus, bukan? Spherical Linear Interpolation (SLERP) sendiri adalah metode interpolasi yang digunakan untuk menginterpolasi antara dua quaternion atau vektor, yang berguna untuk interpolasi rotasi.
Konsep Dasar
Misalkan kita memiliki karakter yang ingin dirotasi dari orientasi q1 (rotasi awal) ke q2 (rotasi akhir). Dalam setiap frame, kita akan menghitung interpolasi berdasarkan waktu atau frame saat ini, dengan persamaan:
Dan implementasinya pada sebuah library (raymath.h) yang digunakan pada game engine “homemade” saya seperti ini:
// Copyright : https://github.com/raysan5/raylib/blob/master/src/raymath.h
// Calculates spherical linear interpolation between two quaternions
RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
{
Quaternion result = { 0 };
#if !defined(EPSILON)
#define EPSILON 0.000001f
#endif
float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
if (cosHalfTheta < 0)
{
q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w;
cosHalfTheta = -cosHalfTheta;
}
if (fabsf(cosHalfTheta) >= 1.0f) result = q1;
else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
else
{
float halfTheta = acosf(cosHalfTheta);
float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);
if (fabsf(sinHalfTheta) < EPSILON)
{
result.x = (q1.x*0.5f + q2.x*0.5f);
result.y = (q1.y*0.5f + q2.y*0.5f);
result.z = (q1.z*0.5f + q2.z*0.5f);
result.w = (q1.w*0.5f + q2.w*0.5f);
}
else
{
float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta;
float ratioB = sinf(amount*halfTheta)/sinHalfTheta;
result.x = (q1.x*ratioA + q2.x*ratioB);
result.y = (q1.y*ratioA + q2.y*ratioB);
result.z = (q1.z*ratioA + q2.z*ratioB);
result.w = (q1.w*ratioA + q2.w*ratioB);
}
}
return result;
}
Dengan SLERP, rotasi karakter akan dilakukan secara halus dan natural, mengikuti lintasan rotasi di unit quaternion. Ini sangat berguna ketika karakter harus menghadap ke arah tertentu dengan cara yang halus.
Implementasi
Lalu bagaimana implementasinya ke kode sebelumnya? Pada kode sebelumnya kita hanya perlu menambahkan beberapa kode sesuai dengan rumus matematis dari Spherical Linear Interpolation (SLERP). Yang pada implementasi ini, q1 saya beri nama “currentRotation” dan q2 saya beri nama “targetRotation”, sedangkan “t” nya adalah “rotationSpeed”. Yang dimana sesuai namanya “targetRotation”-nya mengikuti arah dimana titik target diletakan dan “currentRotation” adalah rotasi saat ini. Sehingga dari kode sebelumnya kita hanya perlu menambahkan beberapa kode seperti ini:
- Sebelum:
................................................................
if (onMove)
{
_position = _position + Vector3Scale(direction, _movementSpeed * GetFrameTime());
_rotation = QuaternionFromDirection(direction);
}
................................................................
- Sesudah:
................................................................
if (onMove)
{
float rotationSpeed = 5.0f * GetFrameTime();
Quaternion currentRotation = _rotation;
Quaternion targetRotation = QuaternionFromDirection(direction);
_rotation = QuaternionSlerp(currentRotation, targetRotation, rotationSpeed);
_position = _position + Vector3Scale(direction, _movementSpeed * GetFrameTime());
}
................................................................
Untuk full source code nya, bisa teman-teman unduh di:
Kesimpulan
Quaternion adalah konsep matematika yang luar biasa, memungkinkan rotasi 3D yang lebih halus dan efisien dibandingkan metode lainnya. Dan Spherical Linear Interpolation (SLERP) adalah metode yang efektif untuk interpolasi rotasi, khususnya dalam animasi 3D. Dengan SLERP, transisi rotasi antara dua orientasi dilakukan secara halus dan natural, mengikuti lintasan rotasi di unit quaternion.
Referensi:
Post by: Wildan