Bagaimana Anda bisa mengekstrak orientasi dari matriks transformasi?

10

Saya memiliki matriks transformasi 4x4 M, dan saya ingin mengetahui bentuk bola ketika ditransformasikan oleh M. (Sphere berada pada titik asal dan memiliki jari-jari 1.)

Saya tahu saya dapat menemukan pusat dengan hanya mengalikan M dengan (0,0,0,1).

Namun, jari-jari menjadi masalah karena M dapat menekan dan memutar bola. Bagaimana saya bisa mengetahui radius baru ellipsoid yang dihasilkan? Apakah ada cara untuk mengetahui orientasinya?

Lebih khusus lagi, saya perlu mengetahui ukuran bola pembatas yang akan melingkupi bola yang berubah. Dengan kata lain, berapakah maksimum | M * V - M * (0,0,0,1) |, di mana V adalah vektor satuan (titik pada bola asli).

Kapten Kodeman
sumber
1
Tidak bisakah Anda menghitung panjang vektor sumbu yang ditransformasikan? (3 kolom dari bagian rotasi matriks Anda) Bola pembatas akan memiliki jari-jari yang sama dengan panjang vektor terpanjang.
Bart
Tidak, saya pikir itu tidak benar. Arah terpanjang mungkin tidak selaras sumbu. (Bayangkan jika Anda remas, putar, remas lagi, putar lagi, dll.)
CaptainCodeman
Hmm, tidak yakin itu penting. Jika saya berhasil meyakinkan diri sendiri, saya akan menulis jawaban hari ini. ;)
Bart
Masalahnya adalah, jika Anda melakukan transformasi SCALE, vektor-vektor dasar dari matriks M tidak harus tetap ORTHOGONAL satu sama lain.
GPUquant

Jawaban:

6

Secara matematis, jumlah yang Anda tanyakan disebut norma operator . Sayangnya, tidak ada formula sederhana untuk itu. Jika ini merupakan transformasi affine yang sepenuhnya umum - misalnya, jika bisa memiliki kombinasi rotasi dan skala tidak seragam yang sewenang-wenang, dalam urutan apa pun - maka saya khawatir tidak ada yang bisa dilakukan selain menggunakan dekomposisi nilai singular . Jika Anda menerapkan SVD ke matriks Anda, maka nilai singular terbesar adalah jari-jari maksimum ellipsoid yang dihasilkan. Nilai singular lainnya juga akan menjadi dua jari-jari lainnya, dan prosedur SVD juga dapat mengekstrak orientasi sumbu untuk Anda.

Menerapkan SVD bukan untuk menjadi lemah hati, karena melibatkan menemukan nilai eigen. Jika semua yang Anda inginkan adalah nilai singular sendiri, mereka adalah akar kuadrat dari nilai eigen M ^ T * M. Jadi jika Anda memiliki pemecah nilai eigen 3x3 berguna, atau Anda tidak keberatan menulisnya, Anda dapat menggunakannya. Jika Anda ingin mengekstrak orientasi sumbu juga, maka itu akan lebih terlibat karena Anda harus menemukan vektor eigen juga. Pada artikel Wikipedia itu ada daftar tautan ke perpustakaan untuk melakukan SVD, salah satunya dapat Anda gunakan dalam proyek Anda.

Jika bentuk matriks Anda dibatasi sedemikian rupa sehingga skala tidak seragam terjadi paling banyak sekali dan merupakan transformasi pertama yang diterapkan, yaitu paling kanan ketika Anda menggunakan vektor kolom, maka Anda dapat menyederhanakan ini untuk hanya melihat panjang dari vektor sumbu yang ditransformasikan. Dalam kasus itu saja - yaitu skala tunggal tidak seragam diikuti oleh urutan rotasi, refleksi, dan skala seragam - hanya dengan melihat vektor sumbu akan memberikan jawaban yang tepat.

Nathan Reed
sumber
Terima kasih, saya menghargai tanggapan terperinci. Di mana dekomposisi yang disediakan dalam jawaban lain gagal berfungsi?
CaptainCodeman
2
@ KaptenCodeman Jawaban lain hanya melihat vektor sumbu yang ditransformasikan (yaitu kolom dari matriks), seperti apa yang saya jelaskan di paragraf ketiga saya. Gagal dalam kasus ada skala tidak seragam setelah rotasi, sejak itu penskalaan tidak berlaku di sepanjang sumbu asli.
Nathan Reed
2

Mungkin mengekstrak faktor skala dari matriks dan kemudian menggunakan nilai maksimal komponennya. Menggunakan matriks SRT (Scale-Rotation-Translation) Anda dapat melakukan ini seperti itu:

glm::mat4 m = ...;
// Extract col vectors of the matrix
glm::vec3 col1(m[0][0], m[0][1], m[0][2]);
glm::vec3 col2(m[1][0], m[1][1], m[1][2]);
glm::vec3 col3(m[2][0], m[2][1], m[2][2]);
//Extract the scaling factors
glm::vec3 scaling;
scaling.x = glm::length(col1);
scaling.y = glm::length(col2);
scaling.z = glm::length(col3);

float scaleFactor = MAX(scaling.x, MAX(scaling.y, scaling.z));

(berdasarkan http://wklej.org/id/950061/ - namanya teruraiTRS dan tidak teruraiSRT karena saya menggunakan nama-nama yang dipesan sesuai urutan matriks yang dikalikan dalam OpenGL).

Sekarang Anda dapat mengalikan jari-jari bola asli dengan scaleFactor dan Anda memiliki bola batas Anda.

membalikkan
sumber