Kuaterniyonları Kullanma: Onlarla ne yapabilirim? (matematik olmadan)


24

Oyun Geliştiricisiyim ve Matematik çalışmadım. Bu yüzden sadece Quaternions'ı bir araç olarak kullanmak istiyorum. Ve 3D döndürme ile çalışabilmek için, Quaternions (Veya Matrisler) kullanmak gereklidir, ancak bu Soru'da Quaternions'da kalalım. Birçok geliştiricinin bunları kullanmasının önemli olduğunu düşünüyorum. Bu yüzden bilgimi paylaşmak ve umarım sahip olduğum delikleri doldurmak istiyorum. Şimdi ....

Anladığım kadarıyla:

Bir Quaternion 2 şeyi tanımlayabilir:

  1. 3B Nesnenin geçerli yönü.
  2. Bir Nesnenin yapabildiği dönüş dönüşümü. (RotationChange)

Bir Quaternion ile yapabilirsiniz:

çarpmalar:

  1. Kuaterniyon endOrientation = Kuaterniyon dönüşüDeğiştir * Kuaterniyon akımOritasyonu;

    Örneğin: 3D Nesnem 90 ° sola döndürülmüş - ve benim çarptım çarpım 180 ° sağa dönüyor, sonunda 3D Nesnem 90 ° sağa dönüyor.

  2. Kuaterniyon dönme Değişimi = Quaternion endRotation * Quaternion.Inverse (startRotation);

    Bununla, başka bir Oryantasyona uygulanabilen bir dönüş Değişimi elde edersiniz.

  3. Vector3 endPostion = Kuaterniyon dönme Değişimi * Vector3 currentPosition;

    Mesela: 3D Nesnem Konumda (0,0,0) ve çarptığım rotasyonum 180 ° 'den sağa doğru bir rotasyon, son konumum ise (0, -50,0) gibi bir şey. Bu Kuaterniyonun içinde bir Eksen vardır - ve o eksen etrafında bir dönüş. Sen bu noktayı, Y Degrees ekseni etrafında döndürürsün.

  4. Vector3 rotatedOffsetVector = Kuaterniyon dönüşüDeğiştir * Vector3 currentOffsetVector;

    Örneğin: Başlangıç ​​yönüm YUKARI - (0,1,0) gösteriyor ve çarptığım dönüşüm 180 ° 'den sağa doğru bir dönüş, bitiş yönüm aşağı gösteriyor. (0, -1,0)

Karıştırma (Lerp ve Slerp):

  1. Quaternion currentOrientation = Quaternion.Slerp (startOrientation, endOrientation, enterpolatör)

    enterpolatör 1 ise: currentOrientation = endOrientation

    enterpolatör 0 ise: currentOrientation = startOrientation

    Slerp daha hassas enterpolasyon yapar, Lerp daha fazla performans interpolasyon yapar.

Sorularım):

Şu ana kadar açıkladığım her şey doğru mu?

Quaternions ile yapabileceğiniz "hepsi" mi? (bilmiyorum)

Onlarla başka neler yapabilirsiniz?

Dot ürünü ve 2 Quaternions arasındaki Cross ürünü ne işe yarar?

Düzenle:

Bazı cevaplarla güncellenmiş soru


2 değil, nfarklı yönlerinizin (tutumlar, pozlar, vb.) Olduğunu söyleyin . Daha sonra, ağırlıkları kullanarak ortalamaları slerp / lerp'i genelleştirerek ortalayabilirsiniz. Bir kuaterniyonu, bir katı cisme belirli bir süre için açısal bir hız uygulamasına eşdeğer olan bir rotora dönüştürebilirsiniz. Dolayısıyla açısal hız entegrasyonunu kuaterniyonlarla da tanımlayabilirsiniz. İki yönelimin ne kadar farklı olduğunu da tahmin edebilirsiniz (hiperfer üzerindeki iki kuaterniyonun kapsadığı yayın uzunluğunu hesaplayın).
teodron

Ve evet, ilk bakışta, gerekçeniz doğrudur (kuaterniyon anlayışınız teknik olmayan bir kişi için oldukça iyidir). Bu yorum için uygun değil, tebrikler! Teknik olarak yetenekli bile tüm kuaterniyon kullanımlarını bilmese de, onları bir amaç için sadece yazılım mühendisliği araçları olarak kullanıyorlar.
teodron,

4
“Ve 3D rotasyonla çalışabilmek için Quaternions kullanmak gerekiyor” Bu cümlenin ne kadar yanlış olduğunu vurgulayamıyorum. Oyun geliştirme için Euler veya Tait-Bryan açılarını kullanabilirsiniz, tek sorun gimbal kilidi. Bir oyun geliştiricisi olmak istiyorsan bir noktada matematiğe ihtiyacın olacak, öğren.
Bálint

1
“oyun geliştiricisi” ve “matematik çalışmamak” bir oksimorondur.
Margaret Bloom

2
Soruyla ne yapmaya çalıştığını takdir ediyorum, ancak cevaplar soruda değil cevapta olmalı. Onları harmanlamaya değer olduğunu düşünüyorsanız, bir "özet" cevabı yapın.
Temel

Yanıtlar:


23

Çarpma işlemi

En azından Birliğin Kuaterniyonları uygulaması açısından, soruda açıklanan çarpım sırası doğru değil. Bu önemlidir, çünkü 3D döndürme değişmeli değildir .

Yani, bir nesneyi rotationChangebaşından başlayarak döndürmek currentOrientationistersem, şöyle yazarım:

Quaternion newOrientation = rotationChange * currentOrientation;

(yani, Dönüşümler sola yığılır - Unity'nin matris sözleşmesiyle aynıdır. En sağdaki dönüş ilk / "en yerel" uçta uygulanır)

Bir yönü veya ofseti bir vektörü döndürerek dönüştürmek isteseydim, şöyle yazarım:

Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;

(Aksini yaparsanız Birlik derleme hatası üretecektir)

harmanlama

Çoğu durumda Lerping rotasyonları ile kurtulabilirsiniz. Açısı quaternion içinde "gizli olarak" kullanılacaktır en olmasıdır yarım bir Matrix gibi bir şey daha LERP doğrusal yaklaşım büyük ölçüde yakın yapma, dönme açısı (genelde will not LERP iyi!). Daha fazla açıklama için bu videoya yaklaşık 40 dakika göz atın .

Gerçekten Slerp'e ihtiyaç duyduğunuz durumlardan biri, bir animasyon zaman çizelgesindeki anahtar kareler arasında enterpolasyon yapmak gibi zaman içinde tutarlı hıza ihtiyacınız olduğundadır. Bir çıkışın iki giriş arasında orta olmasına özen gösterdiğiniz durumlarda (bir animasyonun karışım katmanları gibi) o zaman genellikle Lerp oldukça iyi hizmet eder.

Başka?

İççarpım Eğer rotasyonlar karşılaştırmak gerekirse benzerlik ölçüsü olarak nokta ürününü kullanabilirsiniz böylece iki birim kuaterniyonların, aralarındaki açının kosinüs verir. Bu biraz belirsizdir, bu yüzden daha okunaklı kod için sık sık Quaternion kullanırdım.Angle (a, b) , ki bu, açıları karşılaştırdığımızı, açıkça bilinen birimler (derece) cinsinden ifade eder.

Birliğin Kuaterniyonlar için sağladığı bu kolaylık metot tipleri çok faydalıdır. Hemen hemen her projede bunu en az birkaç kez kullanıyorum :

Quaternion.LookRotation(Vector3 forward, Vector3 up)

Bu, şöyle bir kuaterniyon oluşturur:

  • Yerel z + eksenini tam olarak forwardvektör bağımsız değişkeni boyunca gösterecek şekilde döndürür
  • Yerel y + eksenini up, varsa vektör argümanına veya (0, 1, 0)varsa ihmal edildiğinde mümkün olduğu kadar yakın noktaya döndürür

"Yukarı" sadece "olabildiğince yakın" olmasının sebebi sistemin fazla önceden tanımlanmış olmasıdır. Z + 'ya karşı karşıya kalmak forward, iki derece serbestlik kullanmaktır (örneğin, yalpa ve zift);

Oldukça sık buluyorum ki tam tersi özelliklere sahip bir şey istiyorum: yerel y + 'nin tam olarak işaret etmesini upve yerel z +' forwardnın kalan özgürlüğe mümkün olduğunca yaklaşmasını istiyorum .

Bu, örneğin, hareket girişi için kamera-göreli bir koordinat çerçevesi oluşturmaya çalışırken ortaya çıkar: Yerel yukarı yönümün zemine dik ya da eğimli yüzeye normal kalmasını istiyorum, bu yüzden girişim karakteri araziye sokmaya çalışmıyor veya onları havaya kaldırmak.

Bunu ayrıca, bir tankın kulenin mahfazasının bir hedefle yüzleşmesini istiyorsanız, yukarı / aşağı hedef alırken tankın gövdesinden ayrılmadan da alabilirsiniz.

LookRotationAğır kaldırma için bunu kullanarak kendi rahatlık fonksiyonumuzu oluşturabiliriz :

Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
    Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
    Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);

    return rotateZToUp * rotateYToZ;
}

Burada yerel y + 'dan z +' ya ve yerel z + 'y' y 'yi döndürür.

Sonra yeni z + 'yı yukarı yönümüze döndürüyoruz (bu nedenle net sonuç doğrudan y yerel noktalarıdır exactUp) ve yeni y + olumsuz yöndeki ileri yöne mümkün olduğunca yakındır (bu nedenle net sonuç, mümkün olduğu kadar yerel z + noktalarıdır. approximateForward)

Bir başka kullanışlı kolaylık yöntemi de Quaternion.RotateTowards, sıklıkla kullandığım:

Quaternion newRotation = Quaternion.RotateTowards(
                             oldRotation, 
                             targetRotation,
                             maxDegreesPerSecond * Time.deltaTime
                         );

Bu targetRotation, kare hızından bağımsız olarak tutarlı ve kontrol edilebilir bir hızda yaklaşmamızı sağlar - oyun mekaniğinin sonucunu / dürüstlüğünü etkileyen rotasyonlar için önemlidir (bir karakterin hareketini çevirmek veya oyuncu üzerinde bir taret girişi yapmak gibi). Doğal olarak, bu durumda Lerping / Slerping, hareketin yüksek kare hızlarında hızlanmasına neden olarak oyun dengesini etkileyebilir. (Bu yöntemlerin yanlış olduğunu söylemek değildir - adaleti değiştirmeden bunları doğru kullanmanın yolları vardır, sadece özen gerektirir. RotateTowardsBu bizim için ilgilenen uygun bir kısayol sağlar)


İpucu: Video URL’sinin sonuna & t = 40m ekleyin, böylece doğrudan oraya atlayın (isteğe bağlı olarak örneğin 40m5s). Kuaternion nokta ürünleri, küresel oyun dünyalarıyla da ilgilenirken kullanışlı - ya da dönen küre parçalarını yönlendirirken daha geniş bir kullanım alanına sahip.
Luke Briggs,

@Luke Briggs: Küresel oyun dünyası noktası, eğer isterseniz kendi cevabında (özellikle diyagramlarla) ayrıntılandırmaya değecek gibi geliyor. :)
DMGregory

Harika bir fikir - saat 3 oldu (bu yüzden biraz saçma sapan!) Ama yarın birlikte bir şeyler çıkarmaktan mutlu olurum (hatırlarsam!)
Luke Briggs

1
Düzenleme: Bir cevap hakkında düşünerek biraz zorlandım, bu yüzden meydan okuma kabul edildi! En azından kaba bir kesim olarak işaretleyeceğim, böylece insanlar, içine giren geç gece yanmasından haberdar olabilecekler: P
Luke Briggs

Oraya gidiyoruz! Cevabınızı zaten altta yatan fonksiyonları gerçekten iyi kapsayan bir temele dayanarak grafiksel bir genel bakış açısından ele almaya çalıştım. Sanırım biraz uyuma zamanı!
Luke Briggs,

14

Nokta ürünü nerede kullanılıyor?

Birlik'te, nokta ürünün en yaygın kullanıcılarından biri, iki kuaterniyonun ==veya ile eşit olup olmadığını kontrol ettiğinizdedir !=. Unity, dahili x, y, z, w değerlerini doğrudan karşılaştırmak yerine, benzerliği kontrol etmek için nokta ürünü hesaplar. Aramayı, beklediğinizden daha pahalı hale getirdiğinden, bunu akılda tutmaya değer.

Ayrıca ilginç kullanım durumlarında da kullanıyoruz.

Kuaternion nokta ürünleri ile eğlenceli - Küresel dünyalar ve yörüngeler

Tüm gezegenlerin ve hatta tüm güneş sistemlerinin simülasyonları gittikçe yaygınlaşıyor. Bunu gerçek zamanlı olarak çıkarmak için, kuaternion nokta ürününe de ihtiyacımız var. Çoğu. Kuaternion nokta ürünü çok az kullanılmış ancak kesinlikle kullanımları var - Bir göz atalım!

Öncelikle, dikkate almamız gereken bir dizi rotasyonumuz var:

  1. (İsteğe bağlı) Galaktik merkez etrafındaki yıldız
  2. Yıldızın etrafındaki gezegen
  3. Gezegenin eğimi
  4. Gezegenin dönüşü
  5. Yakındaki ızgara hücrelerinin konumu (gezegenlerin çekirdeği etrafında döndürülmüş) *
  6. Çoklu yörünge uçakları

Hepsini bir araya getirin ve çok fazla karmaşıklıkla sonuçlanır (ve çok büyük sayılar!). İzleyici gezegenin yüzeyinde dururken, onların oyun dünyamızda çılgınca bir hızda incinmelerini istemiyoruz. Aslında onların durağan ve kaynağın yakınında bir yerlere gitmesini tercih ederdik - evreni oyuncunun etrafında gezdirin.

Dönen gezegen

Önemli olarak, bu senaryoda gezegenin dönüşünü ve eğimini doğru bir şekilde alabilmemiz için, ekseni direğe kilitlememiz gerekir, böylece sadece yukarıdaki görüntü üzerinde yukarı / aşağı dönebilir (yani oyuncu hareket ederken "yukarı" kuzeyinde). Bir kuaterniyon nokta ürününün geldiği yer burasıdır. Burada bir nokta ürünü kullanmamış ve bunun yerine sadece eğimi çarptıysak, bu olur:

Yanlış eğik 'gezegenler'

Yörüngeli 'gezegenlerimizin kutuplarının her zaman yıldızlara doğru nasıl döndüklerine dikkat edin. Gerçekte olan bu değil - eğim sabit bir yönde .

Çok fazla konu dışı kalmadan, kısa bir özet:

  • Bir kürede, bir oryantasyon ayrıca bir yüzey pozisyonunu da düzgün bir şekilde tarif eder.
  • Bir araya getireceğimiz çok fazla rotasyon var.
  • Her şeyi rotasyon olarak tanımlayın; izleyicinin de konumu. Bu, sonuçta daha az işlem yaptığımız için performansı artırmaya yardımcı olur.
  • Rotasyonlar arasındaki açı (nokta ürünümüz) daha sonra boylamın ölçülmesine yardımcı olur ve özellikle eğikliklerle başa çıkmada iyi çalışır.

Sadece açıyı alarak , bu istenmeyen dönüşlerin bir kısmını düşürürüz . Aynı zamanda , yerel iklimin yanı sıra navigasyon için de yararlı olan bir boylam ölçümü yaptık .

* Gezegenler birçok ızgara hücresinden yapılmıştır . Yalnızca yakındakiler aslında görüntüleniyor.


2
Bu, sahneyi ayarlamak ve sorunu motive etmek için harika bir iş çıkarsa da, kuaterniyon nokta ürününün (yani, birlikte zincirleme için kullandığımız dot(a, b) = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.wkuaternyon bileşiminin aksine skaler ürünün matematiğinin nasıl olduğu konusunda biraz bulanıkım) . rotasyonlar) bu sorunu çözmemize yardımcı olacaktır. Bu konuyu biraz sonra daha ayrıntılı bir şekilde açıklayabilseniz çok mutlu olacağım (Slerlerinizden sizi korumak istemem ... Uykum demek istiyorum!)
DMGregory

@DmGregory kısa cevap tilt tek garip olan; onun dışında her şey güzelce düzenlenir (gezegen yıldızının etrafında sallanıyormuş gibi görünür). (Umarım!) Yarın biraz daha bağlam ekleyeceğim!
Luke Briggs,

@DMGregory Bazı ek bilgiler ekledim (uyuyamadım!) - inşallah bunu daha açık hale getirir.
Luke Briggs,

1
Biraz yoğun olduğum için üzgünüm, ancak birkaç kez yeniden okuduktan sonra, nokta ürünü tanımladığınız dönüşümü elde etmek için formülde nasıl kullanacağımı hala bilmiyorum. Açıkça yaptığınız işlemleri düzenleyen küçük bir sözde kod ekler misiniz?
DMGregory

@DMGregory Kuaterniyonlara aşina değilim ama eğer bu bir küre üzerinde dönüyorsa, o zaman rotasyon kompozisyonları değil. Bu, herhangi bir çevrenin AKA yüzeyindeki bir "çizgi" için normal vektörü hesaplamak üzere vektörlerle küresel geometri kullanıyor. Bir kez daha, cevap çok az anlam ifade etmiyor ve bu soruyu da cevaplamıyor, ancak küresel geometri kullandıklarına inanıyorum.
Büyük Ördek
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.