Saya mencoba untuk membiarkan pengguna aplikasi saya memutar objek 3D yang ditarik di tengah layar dengan menyeret jari mereka di layar. Gerakan horizontal di layar berarti rotasi di sekitar sumbu Y yang tetap, dan gerakan vertikal berarti rotasi di sekitar sumbu X. Masalah yang saya alami adalah bahwa jika saya hanya mengizinkan rotasi di sekitar satu sumbu objek berputar dengan baik, tetapi segera setelah saya memperkenalkan rotasi kedua objek tidak berputar seperti yang diharapkan.
Ini adalah gambar dari apa yang terjadi:
Sumbu biru mewakili sumbu tetap saya. Bayangkan layar memiliki sumbu biru tetap ini. Inilah yang saya ingin objek untuk memutar sehubungan dengan. Apa yang terjadi berwarna merah.
Inilah yang saya tahu:
- Rotasi pertama di sekitar Y (0, 1, 0) menyebabkan model bergerak dari ruang biru (panggil ruang ini A) ke ruang lain (sebut ruang ini B)
- Mencoba memutar lagi menggunakan vektor (1, 0, 0) berputar di sekitar sumbu x di ruang B TIDAK di ruang A yang bukan apa yang saya maksudkan.
Inilah yang saya coba, mengingat apa yang saya (pikirkan) saya tahu (tidak mengikutkan kata W untuk singkatnya):
- Putar pertama di sekitar Y (0, 1, 0) menggunakan Quaternion.
- Konversi rotasi Y Quaternion ke Matrix.
- Kalikan matriks rotasi Y dengan sumbu tetap saya x Vektor (1, 0, 0) untuk mendapatkan sumbu X dalam kaitannya dengan ruang baru.
- Putar sekitar X Vector baru ini menggunakan Quaternion.
Berikut kodenya:
private float[] rotationMatrix() {
final float[] xAxis = {1f, 0f, 0f, 1f};
final float[] yAxis = {0f, 1f, 0f, 1f};
float[] rotationY = Quaternion.fromAxisAngle(yAxis, -angleX).toMatrix();
// multiply x axis by rotationY to put it in object space
float[] xAxisObjectSpace = new float[4];
multiplyMV(xAxisObjectSpace, 0, rotationY, 0, xAxis, 0);
float[] rotationX = Quaternion.fromAxisAngle(xAxisObjectSpace, -angleY).toMatrix();
float[] rotationMatrix = new float[16];
multiplyMM(rotationMatrix, 0, rotationY, 0, rotationX, 0);
return rotationMatrix;
}
Ini tidak berfungsi seperti yang saya harapkan. Rotasi tampaknya bekerja, tetapi pada beberapa titik gerakan horizontal tidak berputar tentang sumbu Y, tampaknya berputar tentang sumbu Z.
Saya tidak yakin apakah pemahaman saya salah, atau jika ada hal lain yang menyebabkan masalah. Saya memiliki beberapa transformasi lain yang saya lakukan pada objek selain rotasi. Saya memindahkan objek ke tengah sebelum menerapkan rotasi. Saya memutarnya menggunakan matriks yang dikembalikan dari fungsi saya di atas, lalu saya menerjemahkan -2 ke arah Z sehingga saya bisa melihat objek. Saya tidak berpikir ini mengacaukan rotasi saya, tetapi di sini adalah kode untuk itu:
private float[] getMvpMatrix() {
// translates the object to where we can see it
final float[] translationMatrix = new float[16];
setIdentityM(translationMatrix, 0);
translateM(translationMatrix, 0, translationMatrix, 0, 0f, 0f, -2);
float[] rotationMatrix = rotationMatrix();
// centers the object
final float[] centeringMatrix = new float[16];
setIdentityM(centeringMatrix, 0);
float moveX = (extents.max[0] + extents.min[0]) / 2f;
float moveY = (extents.max[1] + extents.min[1]) / 2f;
float moveZ = (extents.max[2] + extents.min[2]) / 2f;
translateM(centeringMatrix, 0, //
-moveX, //
-moveY, //
-moveZ //
);
// apply the translations/rotations
final float[] modelMatrix = new float[16];
multiplyMM(modelMatrix, 0, translationMatrix, 0, rotationMatrix, 0);
multiplyMM(modelMatrix, 0, modelMatrix, 0, centeringMatrix, 0);
final float[] mvpMatrix = new float[16];
multiplyMM(mvpMatrix, 0, projectionMatrix, 0, modelMatrix, 0);
return mvpMatrix;
}
Saya sudah terjebak dalam hal ini selama beberapa hari. Bantuan sangat dihargai.
================================================== ================
MEMPERBARUI:
Membuat ini berfungsi di Unity sangatlah mudah. Berikut ini beberapa kode yang merotasi sebuah kubus yang berpusat pada titik asal:
public class CubeController : MonoBehaviour {
Vector3 xAxis = new Vector3 (1f, 0f, 0f);
Vector3 yAxis = new Vector3 (0f, 1f, 0f);
// Update is called once per frame
void FixedUpdate () {
float horizontal = Input.GetAxis ("Horizontal");
float vertical = Input.GetAxis ("Vertical");
transform.Rotate (xAxis, vertical, Space.World);
transform.Rotate (yAxis, -horizontal, Space.World);
}
}
Bagian yang membuat rotasi berperilaku seperti yang saya harapkan adalah Space.World
parameter Rotate
fungsi pada transformasi.
Jika saya bisa menggunakan Unity saya akan, sayangnya saya harus kode perilaku ini sendiri.
Jawaban:
Masalah Anda memiliki disebut kunci gimble . Saya pikir apa yang ingin Anda lakukan disebut rotasi busur . Matematika untuk arcball bisa sangat rumit.
Cara yang lebih sederhana untuk melakukannya adalah menemukan vektor 2d tegak lurus terhadap gesekan 2d di layar.
Ambil vektor dan proyeksikan ke kamera di dekat pesawat untuk mendapatkan vektor 3d di ruang dunia. Ruang layar ke ruang Dunia .
Lalu buat angka empat dengan vektor ini dan gandakan ke gameobject. Mungkin dengan beberapa transisi slurp atau lerp.
Edit:
Unity Example: Dalam contoh unity, keadaan internal rotasi objek game adalah angka empat bukan matriks. Metode transform.rotation menghasilkan angka empat berdasarkan vektor dan sudut yang disediakan dan mengalikan angka empat itu dengan angka empat rotasi objek game. Ini hanya menghasilkan matriks rotasi untuk rendering atau fisika pada titik selanjutnya. Kuota adalah aditif dan menghindari kunci gimble.
Kode Anda akan terlihat seperti ini:
Tutorial ArcBall Rotation Opengl
sumber
Saya bisa mendapatkan rotasi yang diharapkan dengan memutar matriks rotasi terakumulasi.
sumber
Gambar Anda sesuai dengan kode matrixMatrix Anda, dengan memutar sumbu x dengan rotasi y Anda sebelumnya, Anda mendapatkan sumbu x lokal, ketika Anda kemudian memutar objek di sekitar Anda akan mendapatkan hasil yang Anda tunjukkan dalam gambar Anda. Agar rotasi menjadi logis dari sudut pandang pengguna, Anda ingin memutar objek menggunakan sumbu koordinat dunia.
Jika Anda ingin pengguna Anda dapat memutar objek Anda berkali-kali, masuk akal untuk menyimpan rotasi Anda dalam angka empat bukan matriks, seiring waktu beberapa putaran (dan ketidaktepatan titik mengambang) akan menyebabkan matriks terlihat semakin tidak mirip sebuah matriks rotasi, hal yang sama terjadi dalam angka empat tentu saja, tetapi hanya dengan menormalkan angka empat akan membawanya kembali ke rotasi yang baik.
Cukup gunakan angka empat identitas sebagai nilai awal, dan setiap kali pengguna menggesek layar Anda memutar angka empat Anda dengan
Quaternion.fromAxisAngle(yAxis, -angleX)
kode. Selalu menggunakan (1,0,0,1) untuk rotasi x dan (0,1,0,1) untuk rotasi y.Karena Anda tidak menyebutkan bahasa atau kerangka kerja tertentu, metode pada Quaternion mungkin disebut sesuatu yang berbeda tentu saja, dan normalisasi tidak diperlukan untuk memanggil itu sering, tetapi karena rotasi berasal dari pengguna menggesek layar mereka tidak akan memperlambat banyak hal dan dengan demikian tidak ada kemungkinan Quaternion menyelinap pergi dari unit angka empat.
sumber
myRotation = rotationX.rotate(rotationY).rotate(myRotation).normalize()
Mereka tidak komutatif sehingga urutan yang Anda lakukan diperhitungkan. Tambahkan komentar lain dengan kerangka / bahasa Anda jika itu tidak berhasil dan saya akan menggali lebih dalam lagi.