Vector3'ü bir kuaterniyonla döndürme


25

Bir vektör3'ü belirli bir kuaterniyonla döndürmeye çalışıyorum.

Bunun doğru olduğunu biliyorum

v=qvq1

q1 ters olduğunu biliyorum - sadece qmagnitude(q) , ama nasıl bir vektör geri almak için kuaterniyona vektörün çoğalmasını harita mı?

Sana davranabilirsiniz bulduk v bir matris ve dönüştürme olarak q ve q dönüştürmek ardından matrikslere ve v bir vektör bir matristen, ancak bu biraz üst üzerinde sadece bir vektör olsun gibi görünüyor. Kullanabileceğim daha temiz bir uygulama var mı?

Yanıtlar:


36

Nathan Reed ve teodron maruz kaldıkça, bir v vektörünü birim uzunluktaki kuaterniyon q ile döndürmenin tarifi şöyledir:

1) saf Dördey oluşturma p üzerinden v . Bu sadece 0'ın dördüncü koordinatını eklemek anlamına gelir:

p=(vx,vy,vz,0)p=(v,0)

2) q ile önceden çarpın ve q * konjugatı ile çarpın :

p=q×p×q

3) Bu, bir vektöre geri döndürülebilen başka bir saf kuaterniyonla sonuçlanacaktır:

v=(px,py,pz)

vvq


Bu çalışıyor ama optimal olmaktan uzak . Kuaterniyon çarpımları, ton ve ton işlem anlamına gelir. Bunun gibi çeşitli uygulamaları merak ediyordum ve nereden geldiklerini bulmaya karar verdim. İşte bulgularım.

Ayrıca tanımlayabiliriz q , 3-boyutlu bir vektör kombinasyonu olarak U ve skalar s :

q=(ux,uy,uz,s)q=(u,s)

Kuaterniyon çarpımı kuralları ile ve birim uzunluklu kuaterniyonun eşleniği basitçe ters olduğu için:

p=qpq=(u,s)(v,0)(u,s)=(sv+u×v,uv)(u,s)=((uv)(u)+s(sv+u× v)+(sv+u×v)×(u),)=((uv)u+s2v+s(u×v)+sv×(u)+(u×v)×(u),)

Skaler kısım (elipsler), burada ayrıntılı olarak açıklandığı gibi sıfırla sonuçlanır . İlginç olan vektör kısmı, AKA bizim döndürülmüş vektörümüz v ' . Bazı temel vektör kimlikleri kullanılarak basitleştirilebilir :

v=(uv)u+s2v+s(u×v)+s(u×v)+u×(u×v)=(uv)u+s2v+2s(u×v)+(uv)u(uu)v=2(uv)u+(s2uu)v+2s(u×v)

Bu şimdi çok daha uygun ; iki nokta ürün, çapraz ürün ve birkaç ekstra: işlemlerin yaklaşık yarısı. Kaynak kodunda buna benzer bir şey verecek (bazı genel vektör matematik kütüphanelerini varsayarsak):

void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
    // Extract the vector part of the quaternion
    Vector3 u(q.x, q.y, q.z);

    // Extract the scalar part of the quaternion
    float s = q.w;

    // Do the math
    vprime = 2.0f * dot(u, v) * u
          + (s*s - dot(u, u)) * v
          + 2.0f * s * cross(u, v);
}

Daha iyi bir yazılı cevap için şapka çıkartın . Ve çoğu performans düşkününün vektör işlemlerini gerçekleştirmek için gerçekleri kullanma eğiliminde olduğunu göz önünde bulundurarak, oldukça hız kazanırsınız (hatta özellikle akıllı mimarilerde düz kuaterniyon çarpımı için bile).
teodron

Nihai sonuç, Rodrigues’nin rotasyon formülüne benziyor - yine de aynı temel vektörlere sahip; Katsayıların uyuşup uyuşmadığını görmek için bazı trig kimlikleri kazmak zorunda kalacağım.
Nathan Reed

@NathanReed Bu aynı sonuca ulaşmak için başka bir yol gibi görünüyor. Bunun eşleşip eşleşmediğini de bilmek isterim. Bunu işaret ettiğin için teşekkürler!
Laurent Couvidou

1
GLM'nin bunun uygulanmasını kontrol ediyordum ve aşağıdaki gibi biraz farklı uygulanıyor gibi görünüyor: vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0fBu benzer bir optimizasyon mu? Biraz benziyor ama aynı değil - sadece çapraz ürün kullanıyor, nokta ürünü kullanmıyor. Orijinal kaynak kodu, resmi GLM deposununoperator* bir kuaterniyon ve bir vektör alan ( vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v))
j00hi

7

Her şeyden önce, q ^ (- 1) -q / büyüklüğü (q) değildir; q * / (büyüklüğü (q)) ^ 2 (q * eşleniği; gerçekte hariç tüm bileşenleri olumsuzlar). Elbette, tüm kuaternyonlarınız normalize edilmişse, genellikle bir rotasyon sisteminde olacakları için bölmeyi büyüklükten uzak tutabilirsiniz.

Bir vektörle çarpma gelince, bir kuatın gerçek bileşenini sıfıra ve ijk bileşenlerini vektörün xyz değerine ayarlayarak vektörü bir kuaterniyona uzatırsınız. Sonra v 'yi almak için kuaterniyon çarpımlarını yaparsınız ve sonra ijk bileşenlerini tekrar çıkartırsınız. (V 'nin asıl kısmı her zaman sıfır, artı ya da eksi bazı kayan nokta hatalarından oluşmalıdır.)


5

İlk gözlem: Bunun tersi qdeğil -q/magnitude(q), bu tamamen yanlıştır. Kuaterniyonlu rotasyonlar, bu 4D kompleks sayı eşdeğerlerinin üniter normlara sahip olduğunu, dolayısıyla bu 4D uzayda S3 ünite küresinde bulunduğunu belirtir. Bir kuatın üniter olduğu gerçeği, norm olduğu norm(q)^2=q*conjugate(q)=1ve bu kuatın tersinin eşleniği olduğu anlamına gelir.

Bir birim kuaterniyon q=(w,x,y,z)= (cos (t), sin (t) v )conjugate(q)=(w,-x,-y,-z) olarak yazılırsa , eşleniği = (cos (t), - sin (t) v ), burada t , dönme açısının yarısıdır ve v dönme eksenidir (bir birim vektör olarak, elbette).

Bu Hamilton dude daha yüksek boyutlarda karmaşık sayı eşdeğerleri ile oynamaya karar verdiğinde, aynı zamanda bazı güzel özelliklere tökezledi. Eğer tamamen saf quaternion istihdam Örneğin, q=(0,x,y,z)(hayır skaler bölüm w !), Bir vektör olarak o saçmalıkları düşünebiliriz (aslında insanlar S2 küredir S3 kürenin ekvatoru diyebilirsiniz bir dörtlü var! ! - 19. yüzyıldaki insanların teknik olarak nasıl zarar gördüklerini düşünürsek, bugünlerde telefon kovboylarına göz kulak oluyoruz. Böylece Hamilton bu vektörü kuat formunda aldı: v=(0,x,y,z)ve kuatların geometrik özelliklerini göz önüne alarak bir dizi deney yaptı .. Uzun lafın kısası:

INPUT: _v=(x,y,z)_ a random 3D vector to rotate about an __u__ unit axis by an angle of _theta_

OUTPUT: q*(0,_v_)*conjugate(q)

nerede

 q = (cos(theta/2), sin(theta/2)*u)
 conjugate(q) = inverse(q) = (cos(theta/2), -sin(theta/2)*u)
 norm(q)=magnitude(q)=|q|=1

Gözlem: q * (0, v) * konn (q), formdaki başka bir kuat (0, v ') olmalıdır. Bunun neden olduğunu açık bir şekilde karmaşık olan tüm açıklamalardan geçmeyeceğim, ancak bu yöntemle saf bir hayali kuaterniyon (veya bizim durumumuzdaki bir vektör!) Döndürürseniz, benzer bir nesne elde etmelisiniz: saf hayali kuat. ve sonuç olarak hayali rolünü alırsın. Orada, bir ceviz (ty) kabuğundaki kuaterniyonlarla dönmenin harika dünyası var.

NOT : Bu aşırı kullanılmış ifadeyle kimseye atlayan: bırakma iyidir, çünkü onları kilitlemekten korurlar. Önce hayal güçlerinin kilidini açmaları gerekir !! Quatlar sadece "zarif" bir matematiksel aparattır ve diğer yaklaşımlar kullanılarak tamamen önlenebilir, bunlardan biri geometrik olarak eksen açısı yaklaşımı olarak tamamen eşdeğer buluyorum.

KOD : C ++ kütüphanesi benim için oldukça basit, ancak bir 3D grafik deneycisinin 15 dakikadan fazla zaman kaybetmeden gerekmesi gereken tüm matris, vektör ve quat işlemlerine sahip. Bunu kullanarak yazdığım şeyleri test edebilirsiniz. C ++ acemi değilseniz 15 dakika içinde. İyi şanslar!


Notunuz için +1. Bahse girerim çoğu insan denedilerse gerçek bir gimbal kilidi elde edemediler.
Steve H

Çoğu insan uygun bir yalpalama mekanizması kuramaz ve 3 dönme matrisini bir araya getirirlerse, otomatik olarak "Euler açıları" ifadesiyle sonuçlanabileceğini düşünemezler. Gimbal şeyi sadece en basit robot-kol-kol türlerinden biridir ters kinematik yapmaya çalışırken fazlalık hissedebilecek eklemler (gerçekte istenen yönlendirmeyi oluşturması gerekenden daha fazla serbestlik derecesine sahiptir). Pekala, bu başka bir konu, fakat bu "efsanevi" konunun CG programcıları arasında yarattığı yutturmacadan uzak
durmanın iyi olacağını düşündüm

Nitpickery: Eksen açısı her iki gösterimin de SO (3) 'deki tüm dönüşleri benzersiz şekilde (tamam, her zamanki çift örtüyü modulo olarak) gösterebilmesi ve eşdüzeyde kuaterniyonlar arasında neredeyse önemsiz bir dönüşüm olmasıyla eşdeğerdir. diğer matris olmayan gösterimlerin hepsinden daha kolay oluşturmanın avantajı.
Steven Stadnicki,

Herhangi bir nesne yönelimli programlama dilinde iyi davranışları nedeniyle, özellikle operatör aşırı yükü kullanırken, daha kolay oluşturma avantajına sahiptirler. Emin değilim ama belki de küresel enterpolasyon özellikleri bile eksen açısı için korur (SQUAD belki ?! hariç).
teodron


-1

Bunu el ile halletmeye çalıştım ve aşağıdaki denklem / yöntemi kullandım:

// inside quaterion class
// quaternion defined as (r, i, j, k)
Vector3 rotateVector(const Vector3 & _V)const{
    Vector3 vec();   // any constructor will do
    vec.x = 2*(r*_V.z*j + i*_V.z*k - r*_V.y*k + i*_V.y*j) + _V.x*(r*r + i*i - j*j - k*k);
    vec.y = 2*(r*_V.x*k + i*_V.x*j - r*_V.z*i + j*_V.z*k) + _V.y*(r*r - i*i + j*j - k*k);
    vec.z = 2*(r*_V.y*i - r*_V.x*j + i*_V.x*k + j*_V.y*k) + _V.z*(r*r - i*i - j*j + k*k);
    return vec;
}

Birisi mt derivasyon üzerine bakarsa çok sevinirim, kullandığım http://pastebin.com/8QHQqGbv Yan kaydırmayı destekleyen bir metin editörüne kopyalamayı öneririm

notasyonumda q ^ (- 1) 'yi konjugat, ters değil ve farklı tanımlayıcıları ifade etmek için kullandım, ancak bunun izlenebilir olduğunu umuyorum. Çoğunluğun, özellikle vektörün gerçek kısmının kanıtlanmasının ortadan kalkacağı yerde haklı olduğunu düşünüyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.