Biriken matris dönüşümleri kullanılarak gimbal kilitli problem nasıl çözülür?


12

Jason L. McKesson'un online "Modern 3D Grafik Programlamayı Öğrenme" kitabını okuyorum

Şu an itibariyle, gimbal kilit problemine ve kuaterniyonlar kullanarak nasıl çözüleceğine bağlıyım.

Ancak burada, Kuaterniyonlar sayfasında .

Sorunun bir parçası, bir yönlendirmeyi 3 birikmiş eksenel rotasyon serisi olarak depolamaya çalışmamızdır. Yönelimler, döndürmeler değil, yönelimlerdir. Ve yönelimler kesinlikle bir dizi rotasyon değildir. Bu yüzden geminin yönünü belirli bir miktar olarak bir yönelim olarak ele almalıyız.

Sanırım bu kafam karışmaya başladığım ilk nokta, çünkü yönler ve rotasyonlar arasındaki dramatik farkı görmüyorum. Bir oryantasyonun neden bir dizi rotasyon ile temsil edilemediğini de anlamıyorum ...

Ayrıca:

Bu amaca yönelik ilk düşünce, yönelimi bir matris olarak tutmak olacaktır. Yönlendirmeyi değiştirme zamanı geldiğinde, sonucu yeni akım yönü olarak depolayarak bu matrise basitçe bir dönüşüm uygularız.

Bu, geçerli yönlendirmeye uygulanan her sapma, eğim ve yuvarlanmanın o geçerli yönlendirmeye göre olacağı anlamına gelir. Tam da ihtiyacımız olan şey bu. Kullanıcı pozitif bir sapma uygularsa, sapmanın bazı sabit koordinat sistemlerine göre değil, mevcut işaret ettikleri yere göre döndürmesini istersiniz.

Kavram, anlıyorum, ancak matris dönüşümleri biriktirmek bu soruna bir çözüm olup olmadığını nasıl anlayamıyorum , önceki sayfada verilen kod sadece bu değil.

İşte kod:

void display()
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutil::MatrixStack currMatrix;
    currMatrix.Translate(glm::vec3(0.0f, 0.0f, -200.0f));
    currMatrix.RotateX(g_angles.fAngleX);
    DrawGimbal(currMatrix, GIMBAL_X_AXIS, glm::vec4(0.4f, 0.4f, 1.0f, 1.0f));
    currMatrix.RotateY(g_angles.fAngleY);
    DrawGimbal(currMatrix, GIMBAL_Y_AXIS, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
    currMatrix.RotateZ(g_angles.fAngleZ);
    DrawGimbal(currMatrix, GIMBAL_Z_AXIS, glm::vec4(1.0f, 0.3f, 0.3f, 1.0f));

    glUseProgram(theProgram);
    currMatrix.Scale(3.0, 3.0, 3.0);
    currMatrix.RotateX(-90);
    //Set the base color for this object.
    glUniform4f(baseColorUnif, 1.0, 1.0, 1.0, 1.0);
    glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));

    g_pObject->Render("tint");

    glUseProgram(0);

    glutSwapBuffers();
}

Anladığım kadarıyla, yaptığı şey değil (yığın üzerindeki bir matrisi değiştirmek) biriken matrisler olarak kabul edildi, çünkü yazar tüm bireysel dönüş dönüşümlerini yığının üstünde depolanan bir matrise birleştirdi.

Bir matris anlayışım, bir kökene (yani ... modele) göre bir nokta almak ve onu başka bir kökene (kamera) göre yapmak için kullanıldıklarıdır. Eminim ki bu güvenli bir tanımdır, ancak bu gimbal kilit problemini anlamamı engelleyen eksik bir şey var gibi hissediyorum.

Bana mantıklı gelmeyen bir şey var: Eğer bir matris iki "boşluk" arasındaki göreceli farkı belirlerse, Y ekseni etrafında bir dönüş gelelim, yani rulo, noktayı "boşluk" "Bu daha sonra bu ruloya göre bir kez daha dönüştürülebilir ... Başka bir deyişle, bu noktaya başka dönüşümler bu yeni" rulo boşluğu "ile ilişkili olmamalı ve bu nedenle rotasyonun bir öncekine göreli olmaması gerekir" model alanı "olan gimbal kilide neden oluyor.

Bu yüzden gimbal kilit doğru değil mi? Çünkü nesneyi kendi göreli eksenleri etrafında döndürmek yerine X, Y ve Z eksenleri etrafında döndürüyoruz . Yoksa yanılıyor muyum?

Görünüşe göre bağlandığım bu kod bir matris dönüşümü birikimi olmadığından, bu yöntemi kullanarak bir çözüm örneği verebilir misiniz?

Özet olarak:

  • Döndürme ve yönlendirme arasındaki fark nedir?
  • Kod neden matris dönüşümlerinin birikimi örneğinde değil?
  • Eğer yanlış yapmış olsaydım, bir matrisin gerçek, özel amacı nedir?
  • Matris dönüşümlerinin birikimi kullanılarak gimbal kilit problemine bir çözüm nasıl uygulanabilir?
  • Ayrıca, bir bonus olarak: Döndürmeden sonraki dönüşümler neden hala "model uzayı" ile ilgilidir?
  • Başka bir bonus: Bir dönüşümden sonra, akıma göre daha fazla dönüşüm gerçekleşeceği varsayımında yanlış mıyım?

Ayrıca, ima edilmemişse, OpenGL, GLSL, C ++ ve GLM kullanıyorum, bu yüzden bunlar açısından örnekler ve açıklamalar gerekli değilse büyük beğeni topluyor.

Daha fazla detay daha iyi!

Şimdiden teşekkürler.

Yanıtlar:


11

Bunu önceden anlatmak için iyi bir yol olduğundan emin değilim, umarım sonunda güzelce bağlanır. Diyelim ki, dalış yapalım:

Bir rotasyon ve yönelim farklıdır çünkü birincisi bir dönüşümü ve ikincisi bir durumu tanımlar. Döndürme, bir nesnenin yönlendirmeye nasıl girdiği ve yön , nesnenin yerel olarak döndürülmüş alanıdır . Bu doğrudan ikisinin matematiksel olarak nasıl temsil edildiği ile ilgili olabilir: bir matris, bir koordinat uzayından diğerine dönüşümleri depolar (bunu doğru yaptıysanız) ve bir kuaterniyon doğrudan bir yönelimi tanımlar. Bu nedenle matris, nesnenin sadece bir dizi döndürme yoluyla nasıl bir yönlendirmeye girdiğini açıklayabilir . Bununla ilgili sorun Gimbal Lock.

Gimbal kilit, bir nesneyi bir dizi rotasyon kullanarak bir yönlendirmeye sokmanın zorluğunu gösterir. Sorun, dönme eksenlerinden en az ikisi hizalandığında oluşur:

Görüntü deepmesh3d.com izniyle
Yukarıdaki sol resimde, mavi ve turuncu eksenler aynı dönüşü yapıyor! Bu bir sorundur, çünkü bu, üç serbestlik derecesinden birinin kaybolduğu ve bu noktadan itibaren ek rotasyonların beklenmedik sonuçlar doğurabileceği anlamına gelir. Kuaterniyonları kullanmak bunu çözer, çünkü bir nesnenin yönelimini dönüştürmek için bir kuaterniyon uygulamak, dönüşümü yuvarlanma, eğim ve sapma işlemlerine dönüştürmek yerine, nesneyi doğrudan yeni bir yöne (bunu söyleyebileceğim en iyi yol) koyacaktır.

Şimdi, aslında matrislerin buna tam bir çözüm olduğu konusunda şüpheliyim, çünkü matrisleri biriktirmek (bu nedenle rotasyonları biriktirmek) ilk olarak Gimbal Lock problemine neden olabilecek şeydir. Bir kuaterniyon ile dönüşümü gerçekleştirmenin uygun yolu, bir noktada kuaterniyon çoğalması yapmaktır:

pTransformed = q * pAsQuaternion * qConjugate

veya kuaterniyonu bir matrise dönüştürerek ve bu matrisi kullanarak noktayı dönüştürerek.

Küresel alanda her zaman düz bir matris dönüşü (45 derece yalpalama gibi) tanımlanacaktır. Dönüşümü yerel alanda uygulamak istiyorsanız, dönüşümünüzü o nesnelerin yerel alanına dönüştürmeniz gerekir. Kulağa garip geliyor, bu yüzden ayrıntılı olarak anlatacağım. Rotasyon sırasının önemi burada devreye giriyor. Dönüşümleri takip edebilmeniz için buraya bir kitap almanızı tavsiye ederim.

Kitabı düz bir şekilde başlatın, kapağı tavana bakacak şekilde, sanki onu açmak ve okumaya başlamak üzereymişsiniz gibi yönlendirin. Şimdi kitabın önünü 45 derece yukarı kaldırın (ön kapak kabaca size bakmalıdır):

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(45);

Şimdi, kitabın esnemesini 45 derece ayarlamak istediğinizi varsayalım (bence sağ elle koordinat sistemi varsayıyorum, bu yüzden bu sola doğru değişecek) ve bunun kitabın yereline uygulanmasını istiyorsunuz koordinat alanı, böylece kitabın kapağı hala size dönük:

bookMatrix.RotateY(45);

Sorun şu ki, bu rotasyon global koordinat alanında gerçekleşiyor, bu yüzden kitabın kapağı sağ omzunuza bakacak. Başlıktaki bu değişikliğin yerel koordinat alanında gerçekleşmesi için önce uygulamanız gerekir!

glutil::MatrixStack bookMatrix;
bookMatrix.RotateY(45);
bookMatrix.RotateX(45);

Denemek! Kitabı tekrar tavana bakacak şekilde başlatın. Sapmasını 45 derece değiştirin ve ardından küresel X ekseni boyunca 45 derece eğin (soldan sağa doğru). Bu, kitabın yerel alanında 45 ve 45'lik bir esneme ile beklediğiniz yönelim.

Ne anlama geliyor? Gerçekten tek şey, operasyonların sırası önemlidir. İlk olarak yapılan dönüşümler, daha sonra yapılan dönüşümler bağlamında yerel dönüşümler haline gelir. Kafanı sarmak çok şey oluyor ve bu, kuaterniyonların çok fazla sorundan kurtarmasını sağlıyor. Siparişe bağlı tüm şeyleri atlayın.

Kuaterniyonların sağladığı diğer büyük avantaj, yönelimlerin enterpolasyonuna izin vermeleridir. Euler açıları arasında enterpolasyon yapmaya çalışmak, sipariş bağımlılıkları nedeniyle neredeyse imkansızdır. Kuaterniyonun matematiksel özellikleri, aralarında iyi tanımlanmış küresel doğrusal enterpolasyona izin verir.

Bir şeyleri sarmak ve orijinal sorunuzu ele almak için: dönüşümler dikkatli bir şekilde seçilmeden ve kesin bir şekilde uygulanmadıkça, biriken matris dönüşümleri Gimbal kilit problemini gerçekten çözmez. Bu nedenle, her zaman kuaterniyon kullanın ve kuaterniyon çarpımını kullanarak noktalara kuaterniyon uygulayın.

Bu yardımcı olur umarım :)


4
sadece kayıt için, Euler açıları ile tarif edilirse, kuaterniyonlar hala gimbal kilidi uygulayabilir; aynı hesaplamayı farklı bir şekilde yapacağınız için (matris yerine kuaterniyonlar)
concept3d

1
@ concept3d - bundan bahsettiğiniz için tebrikler! Gimbal mekanizmasının bir dereceye kadar özgürlüğü kaybetmeye neyin yatkın olduğunu anlamak önemlidir: bu, gereğinden fazla belirlenmiş bir denklem sistemini tanımlayan robotik bir eklem gibidir. Bu mekanizmayı kuaterniyonlar, matrisler veya büyü ile inşa ederseniz, yine de belirsizlikler ile sonuçlanırsınız - bunu anlıyor ve gerçek bir çözüm olan ilk etapta kullanmıyor (bazı örnek veya teknik amaçlarla kullanmanız gerekmedikçe) .
teodron

kuaterniyonları hayal etmek zordur, her zaman düşündüğüm şekilde (birim kuaterniyonlar) 3 Küre'lik bir alanı temsil eder, bu nedenle herhangi bir yönelimi temsil edebilirken, Euler açılarının her birinin daireleri / turosları temsil ettiğini anlıyorum, dolayısıyla tam bir küre değil yönelimi temsil etmek için çok doğru bir yol değildir (3 daire / torus, bağımsız olarak
dönmedikleri

1

Matris birikimleri aslında Gimbal kilidini çözebilir. Dönüşleri toplayarak, herhangi bir keyfi dönüşe izin veren gimballer eklersiniz. Ktodisco'nun sağladığı şema sol şemada bir gimbal kilidi gösterir. Bu yönelim için matris şu şekilde tanımlanabilir:

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);

Y gimbal rotasyonu nedeniyle, X ve Z gimballer şimdi kilitlendi, bu yüzden bir derecelik hareketi kaybettik. Bu noktada, bu üç gimbal kullanarak hiçbir sapma (yerel y, küresel z) yoktur. Ama başka bir gimbal ekleyerek y etrafında yerel olarak dönebilirim:

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);
bookMatrix.RotateY(90);

Her yeni yuvarlanma, eğim ve sapma için, bunları tek bir matristen BİRLEŞTİREN başka bir gimbal ekleyin. Böylece her başka bir yerel döndürme gerektiğinde, bir döndürme oluşturulur ve birikim matrisiyle çarpılır. Bölümden bahsedildiği gibi, hala sorunlar var, ancak gimbal kilit bunlardan biri değil.

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.