Bagaimana saya bisa memutar titik arbitrer dalam 3D (bukan asal)?

15

Saya memiliki beberapa model yang ingin saya putar menggunakan angka empat dengan cara normal, kecuali alih-alih rotasi tentang asal, saya ingin sedikit diimbangi. Saya tahu bahwa Anda tidak mengatakan, dalam ruang 3d, bahwa Anda memutar titik; Anda mengatakan Anda memutar tentang sumbu. Jadi saya memvisualisasikannya sebagai memutar tentang vektor yang ekornya diposisikan tidak pada asal lokal.

Semua transformasi affine di mesin rendering / fisika saya disimpan menggunakan SQT (skala, angka empat, terjemahan; sebuah ide yang dipinjam dari buku Game Engine Architecture .) Jadi saya membangun sebuah matriks setiap frame dari komponen-komponen ini dan meneruskannya ke vertex shader. Dalam sistem ini, terjemahan diterapkan, lalu skala, lalu rotasi.

Dalam satu kasus khusus, saya perlu menerjemahkan objek di ruang dunia, skala, dan memutarnya tentang titik yang tidak terpusat pada asal lokal objek.

Pertanyaan: Mengingat kendala sistem saya saat ini yang dijelaskan di atas, bagaimana saya bisa mencapai rotasi lokal yang berpusat pada titik selain titik asal? Otomatis upvote kepada siapa saja yang dapat menggambarkan bagaimana melakukan ini hanya dengan menggunakan matriks :)

notlesh
sumber
Quaternions sudah menggambarkan rotasi tentang sumbu arbitrer; apakah Anda memiliki masalah dalam membangun angka empat dari data yang Anda miliki?
Martin Sojka
3
Serius, dapatkah orang-orang yang memilih jawaban benar-benar membacanya ? Saya memberikan metode, formula yang efisien, dan bahkan demonstrasi. Namun satu-satunya jawaban yang dibenarkan, sambil memberikan beberapa informasi berharga (dan juga beberapa informasi yang jelas salah), tidak menampilkan semua ini dan bahkan tidak menjawab pertanyaan!
sam hocevar
@ MartinSojka, ini tentang dan titik arbitrer, bukan sumbu arbitrer.
notlesh
@ SamHocevar Kedua jawaban Anda sangat membantu. Saya memilih milik Anda karena lebih teliti dan membantu saya menemukan solusi. Terima kasih semuanya.
notlesh
Ah, maaf - saya bingung dengan Dual Quaternions (itu membuat Anda terjemahan "gratis" juga). Saya akan menulis apa yang saya maksudkan dalam jawaban nanti; mungkin orang lain akan menganggapnya berguna, terutama karena Anda dapat mengurangi tiga komponen menjadi hanya satu - meskipun sedikit lebih rumit.
Martin Sojka

Jawaban:

17

Pendeknya

Anda hanya perlu mengubah T di formulir SQT Anda.

Ganti vektor terjemahan vdengan di v' = v-invscale(p-invrotate(p))mana vvektor terjemahan awal, padalah titik di mana Anda ingin rotasi terjadi, dan invrotatedan invscalemerupakan kebalikan dari rotasi dan skala Anda.

Demonstrasi cepat

Membiarkan pmenjadi titik di mana Anda menerapkan rotasi r. Biarkan smenjadi parameter penskalaan vAnda dan vektor terjemahan Anda. Transformasi matriks akhir T(p)R(r)T(-p)S(s)T(v)bukan R(r)S(s)T(v).

Apa yang Anda inginkan adalah parameter transformasi baru v', r'dan s'transformasi matriks akhir adalah R(r')S(s')T(v')dan kami memiliki:

T(p)R(r)T(-p)S(s)T(v) = R(r')S(s')T(v')

Perilaku tak terhingga menunjukkan bahwa parameter rotasi dan parameter penskalaan tidak dapat berubah (ini dapat diperagakan). Dengan demikian kita memiliki r = r'dan s = s'. Karenanya v', satu-satunya parameter yang hilang adalah vektor terjemahan baru Anda:

T(p)R(r)T(-p)S(s)T(v) = R(r)S(s)T(v')

Jika matriks ini sama, kebalikannya sama:

T(-v)S(-s)T(p)R(-r)T(-p) = T(-v')S(-s)R(-r)

Ini terutama berlaku untuk asal O:

T(-v)S(-s)T(p)R(-r)T(-p)O = T(-v')S(-s)R(-r)O

Menskalakan dan memutar asal menghasilkan asal, dengan demikian mendapatkan:

T(-v)S(-s)T(p)R(-r)(-p) = -v'

v'adalah vektor terjemahan baru yang Anda cari yang memungkinkan Anda menyimpan transformasi Anda dalam bentuk SQT. Mungkin saja menyederhanakan perhitungan; tetapi setidaknya penyimpanan yang dibutuhkan tidak bertambah.

sam hocevar
sumber
Terima kasih untuk penjelasannya. BTW, apakah Anda tahu sumber daya di mana saya bisa membaca lebih lanjut tentang trik representasi SQT?
pachanga
Koreksi saya jika saya salah tetapi sepertinya solusi lain adalah menyimpan Quaternion Anda seperti biasa, dan jika Anda perlu memperhitungkan terjemahan di sekitar titik / poros yang berubah-ubah, maka buatlah matriks Q dengan ini termasuk, cukup ekstrak vektor terjemahan dari matriks ini (kolom terakhir, biasanya) dan menambahkannya ke vektor Terjemahan objek, kemudian membuang matriks sementara Anda.
johnbakers
15

Semua formula rotasi kanonik yang digunakan untuk menurunkan matriks rotasi Anda adalah untuk rotasi tentang asal. Jika Anda ingin menerapkan rotasi di sekitar titik tertentu, Anda harus terlebih dahulu mengimbangi titik asal - atau, ekuivalennya, memindahkan objek sehingga titik yang ingin Anda putar ada di titik asal.

Pertimbangkan kasus 2D terlebih dahulu, karena lebih sederhana dan skala teknik. Jika Anda memiliki kubus lebar 2 yang berpusat pada titik asal dan Anda ingin memutarnya 45 derajat di tengahnya, itu akan menjadi aplikasi sepele dari matriks rotasi 2D .

Tetapi jika sebaliknya Anda ingin memutarnya di sudut kanan atas (terletak di 1,1) Anda harus terlebih dahulu menerjemahkannya sehingga sudut tersebut berada di tempat asalnya. Ini dapat diselesaikan dengan terjemahan -1,-1. Kemudian Anda dapat memutar objek seperti sebelumnya, tetapi Anda harus mengikuti ini dengan menerjemahkannya kembali (oleh 1,1). Jadi secara umum, untuk mencapai matriks rotasi Runtuk rotasi rsekitar titik yang PAnda lakukan:

R = translate(-P) * rotate(r) * translate(P)

di mana translatedan rotatemasing-masing merupakan matriks terjemahan / rotasi kanonik. Seperti yang terjadi, skala ini sepele ke 3D, yang pengecualian harus memasok sumbu untuk rotasi juga - Anda selalu bisa memilih matriks rotasi sumbu X, Y atau Z kanonik, tetapi itu akan membosankan. Anda akan ingin menggunakan matriks rotasi sudut sumbu sewenang - wenang . Jadi final Anda Rdalam 3D adalah:

R = translate(-P) * rotate(a,r) * translate(P)

di mana avektor satuan mewakili sumbu rotasi dan Psekarang menjadi titik 3D dalam ruang model yang mewakili titik rotasi.

Ketika itu terjadi, angka empat dapat dikonversi ke dan dari representasi matriks, sehingga Anda dapat melakukan penggabungan Anda dengan cara yang harus Anda pilih. Atau Anda bisa meninggalkan semuanya sebagai matriks (angka empat memiliki beberapa keuntungan bagus seperti menjadi lebih mudah untuk diinterpolasi dengan cara yang waras, tetapi apakah Anda membutuhkannya atau tidak, itu tergantung pada Anda).

Juga:

Jadi saya memvisualisasikannya sebagai memutar tentang vektor yang ekornya diposisikan tidak pada asal lokal.

Sebenarnya, sementara vektor dapat digunakan untuk mewakili posisi dengan menganggapnya sebagai perpindahan dari suatu asal, vektor tidak memiliki posisi sendiri sehingga agak tidak biasa untuk memvisualisasikannya.


sumber
Terima kasih, ini jawaban yang bagus. Itu tidak sesuai dengan kendala sistem saya. Saya seharusnya memasukkan dalam pertanyaan saya, "apakah mungkin untuk melakukan ini mengingat kendala-kendala ini ?," dan saya pikir jawabannya adalah tidak, karena ini memerlukan dua terjemahan dan saya hanya menyediakan satu. Apakah ini merupakan kekurangan yang tak terhindarkan dari penggunaan SQT sebagai representasi dari transformasi affine?
notlesh
Ini sangat cocok dengan batasan Anda. Matriks R (diproduksi sebagai translate-rotate-translate-back) adalah matriks rotasi Anda. Ganti Q dengan R di sistem "SQT" Anda sehingga Anda memiliki paradigma skala-rotate-terjemahkan yang lebih umum, dan Anda selesai. Terjemahan terakhir itu tidak tergantung pada dua terjemahan perantara yang dilakukan untuk menghasilkan rotasi yang diinginkan.
Anda mengusulkan saya mengganti angka empat dengan matriks? Itu 12 byte lebih per objek (8 jika saya menyimpannya sebagai matriks 4x3)! Saya akan membungkam optimis dalam diri saya, dan memberikan pusaran. (Itu sebenarnya mungkin bahkan tidak akan berjumlah 2kb peningkatan jejak ...) Terima kasih atas tanggapan Anda.
notlesh
Anda dapat - Anda juga dapat mengkonversi di antara mereka, membangun angka empat rotasi dengan cara itu dan memasukkan kembali ke sistem yang ada.
1
@ SamHocevar: Atau, kombinasi apa pun darinya dapat dinyatakan sebagai sekrup tunggal .
Martin Sojka