Bir nesneyi dünyaya hizalı eksenler etrafında nasıl döndürürüm?


15

Her eksen için bir euler açısına sahip bir Vector3 var.

Genellikle, bir döndürme matrisi oluşturmak istediğimde, D3DXMatrixRotationX gibi dönme vektöründen ilgili açıyı geçen fonksiyonları kullanır ve tüm nesne dönüştürme matrisini oluşturmak için kullanılan genel döndürme matrisini oluşturmak için matrisleri (ZXY) çarpar.

Ancak, bu yöntem nesne uzayında bir dizi döndürme üretecektir. Yani, (90, 0, 90) 'ın bir vektörünü yöntemime aktarmak, dünya uzayında etkili bir şekilde (90, 90, 0) bir dönüş yaratacaktır.

Her zaman rotasyon vektörümün her bir bileşeninin ilgili dünya uzay hizalı eksenleri etrafında bir rotasyonla sonuçlanmasını sağlamanın bir yolu var mı?

DÜZENLE:

Bu, şu anda olanların bir animasyonu - Kırmızı değil, mavi eksenlerin etrafında dönmenin bir yolunu istiyorum.

Euler Açıları

DÜZENLEME 2:

Sadece Euler açılarını içeren bir çözüm aramıyorum, sadece dünya eksenleri boyunca birden fazla rotasyonun dönüşümünü temsil edebileceğim bir yol arıyorum.


Sadece differnet işlevlerini üç kez çağırmak ve vektörlerin istemediğiniz kısımlarını filtrelemekle ne sorun var (işlevi çağırmadan önce 0'a ayarlayarak)? Yoksa ne elde etmeye çalıştığınızdan emin değilim.
TravisG

Neleri filtrelemek? Ben 3 ayrı işlevi çağırmak ve daha sonra bunları dönüşüm matrisi oluşturmak için çarpın. Bu yine de yerel bir rotasyona ulaşıyor.
Syntac_

Euler açıları mı yoksa dünya eksenleri hakkında döndürme mi istiyorsunuz? Euler açılarının tanımıyla (örn. En.wikipedia.org/wiki/Euler_angles ), yalnızca alfa açısının kesinlikle bir dünya ekseni ile ilgili olduğunu unutmayın. Diğer iki açı, dünya eksenleri ile uyuşması gerekmeyen eğik eksenlere göredir.
DMGregory

1
Euler açılarını kullanarak tepe noktasına uygulamadan önce üç dönüş matrisini de çarpıyorsunuz. Eğer M, N, O dönme matrisleri ise, sonuç işlemi MNO v'dur . Önerdiğim her matrisi ayrı ayrı uygulamaktır: v1 = O v0, sonra v2 = N v1 ve son olarak v3 = M v2. Bu şekilde her vi dünya koordinatlarında olacak ve dünya koordinatlarında da mevcut eksen için bir döndürme matrisi kullanmanız gerekiyor.
dsilva.vinicius

3
@ dsilva.vinicius Ayrılmış dönüşümleriniz birleştirilmiş dönüşümle tamamen aynıdır ya da başka bir deyişle: MNO v == M * (N * (O v))
GuyRT

Yanıtlar:


1

Yorumlarınıza dayanarak , nesnenin yönünü bir Euler açısı kümesi olarak sakladığınız ve oyuncu nesneyi döndürdüğünde açıları içeri / azalttığınız anlaşılıyor . Yani, bu sahte kod gibi bir şey var:

// in player input handling:
if (axis == AXIS_X) object.angleX += dir;
else if (axis == AXIS_Y) object.angleY += dir;
else if (axis == AXIS_Z) object.angleZ += dir;

// in physics update and/or draw code:
matrix = eulerAnglesToMatrix(object.angleX, object.angleY, object.angleZ);

Charles Beattie'nin belirttiği gibi , rotasyonlar işe gidemediği için, oyuncu nesneyi eulerAnglesToMatrix()rotasyonların uygulandığı sırayla döndürmediği sürece bu beklendiği gibi çalışmaz .

Özellikle, aşağıdaki rotasyon sırasını göz önünde bulundurun:

  1. nesneyi X ekseni etrafında x derece döndürmek ;
  2. nesneyi Y ekseni etrafında y derece döndürmek ;
  3. nesneyi X ekseni çevresinde - x derece döndürmek ;
  4. nesneyi şu şekilde döndür - Y ekseni çevresinde y derece .

Yukarıdaki sahte kodda uygulandığı gibi saf Euler açısı temsilinde, bu dönüşler iptal edilecek ve nesne orijinal yönüne geri dönecektir. Gerçek dünyada, bu gerçekleşmez - bana inanmıyorsanız, altı taraflı bir kalıp veya bir Rubik küpü alın, x = y = 90 ° ve kendiniz deneyin!

Notu olarak çözümü, kendi yanıtında , etmektir bir rotasyon matrisi olarak nesnenin yönünü saklamak kullanıcı girişi dayalı olarak o matrisi (veya bir quaternion) ve günceller. Yani, yukarıdaki sözde kod yerine, böyle bir şey yaparsınız:

// in player input handling:
if (axis == AXIS_X) object.orientation *= eulerAnglesToMatrix(dir, 0, 0);
else if (axis == AXIS_Y) object.orientation *= eulerAnglesToMatrix(0, dir, 0);
else if (axis == AXIS_Z) object.orientation *= eulerAnglesToMatrix(0, 0, dir);

// in physics update and/or draw code:
matrix = object.orientation;  // already in matrix form!

Herhangi bir rotasyon matrisi veya Dördey Euler açıları kümesi olarak temsil edilebilir çünkü (Teknik olarak bir nesnenin oryantasyonunu depolamak için kullanılması da mümkündür. Ancak, Euler açıları iki sıralı dönüşleri birleştirmek için, fiziksel olarak doğru bir kural, her temsil tek bir rotasyona girmek oldukça karmaşıktır ve esas olarak rotasyonları matrislere / kuaterniyonlara dönüştürmek, çoğaltmak ve ardından sonucu tekrar Euler açılarına dönüştürmek anlamına gelir.)


Evet haklısın, çözüm buydu. Bir quaternion gerekli olduğu izlenimini verdiği için bu concept3d'nin cevabından biraz daha iyi olduğunu hissediyorum ama bu doğru değil. Geçerli dönüşü üç Euler açısı olarak değil bir matris olarak sakladığım sürece iyiydi.
Syntac_

15

Dönme problemi, çoğu insan bunu Euler açıları açısından düşünüyor, çünkü anlaşılması kolay.

Yine de çoğu insan Euler açılarının üç ardışık açı olduğu noktasını unutur . Bu, birinci eksen etrafındaki dönüşün bir sonraki dönüşün ilk orijinal dönüşe göreli olacağı anlamına gelir, bu nedenle bir vektörü Euler açılarını kullanarak 3 eksenin her biri etrafında bağımsız olarak döndüremezsiniz.

Bu, iki matrisi çarptığınızda doğrudan matrislere dönüşür, bu çarpmayı bir matrisi diğer matrisin boşluğuna dönüştürmek olarak düşünebilirsiniz.

Bunun, kuaterniyonlar kullanılırken bile 3 ardışık rotasyonda gerçekleşmesi amaçlanmaktadır.

resim açıklamasını buraya girin

Kuaterniyonların kıkırdama kilidi için bir çözüm olmadığı gerçeğini vurgulamak istiyorum . Aslında, kuaternionlar kullanarak Euler açılarını temsil ettiyseniz, kıkırdama kilidi her zaman olacaktır. Sorun sorun, temsili değildir 3 ardışık adımları.

Çözüm?

3 eksen etrafında bir vektör döndürmek için çözüm bağımsız etmektir birleştirmek tek bir eksen ve tek açıyla, bir sıralı çarpma yapmak zorunda nereye adım kurtulmak bu yolla içine. Bu etkili bir şekilde şuna dönüşecektir:

Döndürme matrisim, X ve Y ve Z etrafındaki dönüşün sonucunu temsil eder.

Euler yorumundan ziyade

Döndürme matrisim X, sonra Y sonra Z etrafında dönmeyi temsil eder.

Bunu açıklığa kavuşturmak için wikipedia Euler rotasyon teoreminden alıntı yapacağım:

Euler rotasyon teoremine göre, sabit bir cismin veya Koordinat sisteminin sabit bir nokta etrafında herhangi bir rotasyonu veya rotasyon sırası, sabit noktadan geçen sabit bir eksen (Euler ekseni olarak adlandırılır) etrafında verilen belirli bir açıyla by tek bir rotasyona eşdeğerdir. Euler ekseni tipik olarak u → bir birim vektörü ile temsil edilir. Bu nedenle, üç boyuttaki herhangi bir döndürme, bir u vektörü ve bir skaler combination kombinasyonu olarak temsil edilebilir. Kuaterniyonlar, bu eksen açısı gösterimini dört sayı olarak kodlamak ve R3'teki orijine göre bir noktayı temsil eden bir konum vektörüne karşılık gelen rotasyonu uygulamak için basit bir yol sağlar.

3 matrisin çarpımının her zaman 3 ardışık dönüşü temsil edeceğine dikkat edin .

Şimdi 3 eksen etrafındaki dönüşleri birleştirmek için, X, Y, Z çevresindeki dönüşü temsil eden tek bir eksen ve tek açılar elde etmeniz gerekir. Başka bir deyişle, sıralı rotasyonlardan kurtulmak için bir Eksen / Açı veya kuaterniyon temsili kullanmanız gerekir.

Bu genellikle, genellikle bir kuaterniyon veya eksen açısı olarak temsil edilen bir başlangıç ​​oryantasyonu (oryantasyon bir eksen açısı olarak düşünülebilir) ile başlanarak ve daha sonra hedef oryantasyonunuzu temsil edecek şekilde değiştirilerek yapılır. Örneğin, kimlik dördüncülüğü ile başlar ve hedef yönelime ulaşmak için farkla döndürürsünüz. Bu şekilde herhangi bir özgürlük derecesini kaybetmezsiniz.


Anlaşılır göründüğü gibi cevap olarak işaretlendi.
Syntac_

Bu cevapla ne söylemeye çalıştığınızı anlamakta sorun yaşıyorum. Basitçe "bir nesnenin yönünü Euler açıları olarak saklamayın" mı? Ve eğer öyleyse, neden sadece söylemiyorsunuz?
Ilmari Karonen

@IlmariKaronen Daha açık bir şekilde ifade edilebilir ama bence concept3d eksen açısı gösterimini destekliyor; eksen açısı ve kuaterniyonlar arasındaki ilişki için bu belgenin 1.2.2 bölümüne bakın . Eksen açısı gösteriminin yukarıdaki nedenlerle uygulanması daha kolaydır, gimbal kilitlenmez ve (en azından benim için) Euler açıları kadar kolay anlaşılır.
NauticalMile

@ concept3d, bu çok ilginç ve cevabınızı gerçekten seviyorum. Benim için eksik olan bir şey var, insanlar bir klavye ve fare kullanarak bilgisayarla etkileşime giriyor, eğer fareyi düşünürsek, x ve y fare deltalarından bahsediyoruz. Bu x, y deltalarını, örneğin bir nesne yönünü değiştirmek için, döndürme matrisini oluşturmak için kullanabileceğimiz tek bir kuaterniyonla nasıl temsil edebilirim?
gmagno

@ gmagno yaklaşım genellikle fare hareketini nesneler veya sahneye yansıtmak ve o alandaki deltaları hesaplamaktır, bunu bir ışın yaparak ve kavşak hesaplamaktır. Işın dökümünü, projesini ve projeksiyonunu aramayın, yıllardır CG'de çalışmadığım için detaylar hakkında kaba davranıyorum. umarım yardımcı olur.
concept3d

2

Bir dönüş kombinasyonunu nesne uzayından dünya uzayına değiştirmek çok önemlidir: sadece dönüşlerin uygulanma sırasını tersine çevirmeniz gerekir.

Sizin durumunuzda, matrisleri çarpmak yerine, Z × X × Ysadece hesaplamanız gerekir Y × X × Z.

Bunun için bir gerekçe Wikipedia'da bulunabilir: içsel ve dışsal rotasyonlar arasında dönüşüm .


Bu doğruysa, kaynağınızdaki aşağıdaki ifade doğru olmaz, çünkü rotasyonlar farklı olurdu: "Herhangi bir dış rotasyon, aynı açılardan ancak ters rotasyon sırası ile içsel rotasyona eşdeğerdir ve tersi de geçerlidir. ."
Syntac_

1
Burada bir çelişki görmüyorum. Hem cevabım hem de bu ifade doğrudur. Ve evet, nesne uzayında ve dünya uzayında rotasyon yapmak farklı rotasyonlar verir; asıl mesele bu, değil mi?
sam hocevar

Bu ifade, siparişin değiştirilmesinin her zaman aynı dönüşle sonuçlanacağını söylüyor. Eğer bir emir yanlış rotasyonu üretiyorsa, diğer emir de bir çözüm değildir.
Syntac_

1
Yanlış okuyorsun. Sırayı değiştirmek aynı dönüşle sonuçlanmaz. Sırasını değiştirme ve dış rotasyona içsel rotasyonlardan geçiş aynı dönüş ile sonuçlanır.
sam hocevar

1
Sorunu anladığımı sanmıyorum. GIF'iniz yaklaşık 50 derece Z(nesne alanı), sonra 50 derece X(nesne alanı), sonra 45 derece Y(nesne alanı) döndürme gösterir . Bu, yaklaşık 45 derece Y( dünya boşluğu ), sonra 50 derece X( dünya boşluğu ), sonra 50 derece Z( dünya boşluğu ) dönüşü ile aynıdır .
sam hocevar

1

Birisi bunun neden çalıştığını açıklayabilene kadar çözümümü cevap olarak vereceğim.

Döndürdüğüm vektörde saklanan açıları kullanarak kuaterniyonumu yeniden oluşturduğum ve ardından kuaterniyonu son dönüşümüme uyguladığım her render.

Ancak dünya eksenleri etrafında tutmak için, tüm kareler arasında kuaternion korumak ve sadece açı farkı kullanarak nesneleri döndürmek zorunda kaldım, yani ..

// To rotate an angle around X - note this is an additional rotation.
// If currently rotated 90, apply this function with angle of 90, total rotation = 180.
D3DXQUATERNION q;
D3DXQuaternionRotation(&q, D3DXVECTOR3(1.0f, 0.0f, 0.0f), fAngle);
m_qRotation *= q; 

//...

// When rendering rebuild world matrix
D3DXMATRIX mTemp;
D3DXMatrixIdentity(&m_mWorld);

// Scale
D3DXMatrixScaling(&mTemp, m_vScale.x, m_vScale.y, m_vScale.z);
m_mWorld *= mTemp;

// Rotate
D3DXMatrixRotationQuaternion(&mTemp, m_qRotation);
m_mWorld *= mTemp;

// Translation
D3DXMatrixTranslation(&mTemp, m_vPosition.x, m_vPosition.y, m_vPosition.z);
m_mWorld *= mTemp;

(Hazır olma durumu için ayrıntılı bilgi)

Bence dsilva.vinicius bu noktaya gelmeye çalışıyordu.


1

Dönüşlerin sırasını saklamanız gerekecektir.

Rotating around x 90 then rotate around z 90 !=
Rotating around z 90 then rotate around x 90.

Mevcut rotasyon matrisinizi saklayın ve her rotasyonu geldikçe çarpın.


0

@ Concept3d cevabına ek olarak dünya koordinatlarında eksen etrafında dönebilmek için 3 dışsal dönme matrisi kullanabilirsiniz. Wikipedia'dan alıntı :

Dışsal rotasyonlar, sabit koordinat sisteminin xyz eksenleri etrafında meydana gelen temel rotasyonlardır. XYZ sistemi dönerken, xyz sabittir. XYZ örtüşen xyz ile başlayarak, XYZ için herhangi bir hedef yönelime ulaşmak için üç dışsal rotasyonun bir bileşimi kullanılabilir. Euler veya Tait Bryan açıları (α, β, γ) bu elementel rotasyonların genlikleridir. Örneğin, hedef yönelime aşağıdaki gibi ulaşılabilir:

XYZ sistemi z ekseni etrafında α ile döner. X ekseni şimdi x eksenine göre α açısındadır.

XYZ sistemi tekrar x ekseni etrafında β ile döner. Z ekseni şimdi z eksenine göre β açısındadır.

XYZ sistemi z ekseni etrafında üçüncü kez γ ile döner.

Dönme matrisleri, bir dizi dışsal dönüşü temsil etmek için kullanılabilir. Örneğin,

R = Z (γ) Y (β) X (α)

sütun vektörlerini önceden çarpmak için kullanılıyorsa, xyz eksenleri hakkında dışsal rotasyonların bir bileşimini temsil ederken,

R = X (α) Y (β) Z (γ)

"P", sıra vektörlerini sonradan çarpmak için kullanıldığında tam olarak aynı kompozisyonu temsil eder.

Yani ihtiyacınız olan şey, içsel (veya yerel boşluk) rotasyonları kullanarak ne yapacağınıza ilişkin rotasyonların sırasını tersine çevirmektir. @Syntac bir zxy döndürme istedi, bu yüzden aynı sonucu elde etmek için bir yxz dışsal döndürme yapmalıyız. Kod aşağıdadır:

Burada matris değerleri açıklaması .

// Init things.
D3DXMATRIX *rotationMatrixX = new D3DXMATRIX();
D3DXMATRIX *rotationMatrixY = new D3DXMATRIX();
D3DXMATRIX *rotationMatrixZ = new D3DXMATRIX();
D3DXMATRIX *resultRotationMatrix0 = new D3DXMATRIX();
D3DXMATRIX *resultRotationMatrix1 = new D3DXMATRIX();

D3DXMatrixRotationX(rotationMatrixX, angleX);
D3DXMatrixRotationY(rotationMatrixY, angleY);
D3DXMatrixRotationZ(rotationMatrixZ, angleZ);

// yx extrinsic rotation matrix
D3DXMatrixMultiply(resultRotationMatrix0, rotationMatrixY, rotationMatrixX);
// yxz extrinsic rotation matrix
D3DXMatrixMultiply(resultRotationMatrix1, resultRotationMatrix0, rotationMatrixZ);

D3DXVECTOR4* originalVector = // Original value to be transformed;
D3DXVECTOR4* transformedVector = new D3DXVECTOR4();

// Applying matrix to the vector.
D3DXVec4Transform(transformedVector, originalVector, resultRotationMatrix1);

// Don't forget to clean memory!

Birkaç D3DXMATRIX matrisini yeniden kullanabileceğiniz için bu kod en iyi değil didaktiktir.


1
üzgünüm bu doğru değil. matris / vektör çarpımı ilişkilidir. bu, birleşik matris çarpımı ile tamamen aynıdır.
concept3d

Haklısın. Dışsal ve içsel rotasyon kavramlarını karıştırdım.
dsilva.vinicius

Bu cevabı çözeceğim.
dsilva.vinicius

Cevap şimdi düzeltildi.
dsilva.vinicius
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.