2013-05-05 28 views
6

Bir kuaternionda depolanan rotasyonu ile birinci şahıs bir kamerayı kodlamak istiyorum. Ne yazık ki rotasyonda bir sorun var.Bir dördüncüsü tüm eksen boyunca doğru bir şekilde nasıl döndürür?

şu fonksiyon kamerayı döndürmek için sorumludur. Mouse ve Speed parametreleri, fare hareketini ve dönüş hızını geçirir. Daha sonra işlev dönüş quaternion'unu getirir, döndürür ve sonucu kaydeder. Bu arada, türlerin ve işlevlerin nereden geldiği Bullet Physics kullanıyorum. Fare hareket, sana bir el çizimi gösterdiğinde

void Rotate(vec2 Mouse, float Speed) 
{ 
    btTransform transform = camera->getWorldTransform(); 
    btQuaternion rotation = transform.getRotation(); 

    Mouse = Mouse * Speed;     // apply mouse sensitivity 
    btQuaternion change(Mouse.y, Mouse.x, 0); // create quaternion from angles 
    rotation = change * rotation;    // rotate camera by that 

    transform.setRotation(rotation); 
    camera->setWorldTransform(transform); 
} 

çıkan kamera dönüşünü göstermek için. Sol tarafta kameranın gerçekte gösterdiği yanlış rotasyon gösterilir. Sağ tarafta istenen doğru durum gösterilmektedir. Oklar, fareyi yukarı (turuncu) ve aşağı (mavi) hareket ettirirken kameranın nasıl döndüğünü gösterir.

wrong rotation on the left and desired rotation on the right

Gördüğünüz gibi

sürece yaw sıfır olduğu gibi rotasyon doğrudur. Ancak sahip olduğu daha fazla yaw, kameranın döndüğü daireler küçülüyor. Aksine, daireler her zaman bir küre gibi bir boylam boyunca akmalıdır.

ben bak ben bunları doğru döndürmek için nasıl sormak quaternions ile çok aşina değilim.

+0

Fare koordinatları, büyük olasılıkla ekran alanındadır; bu, onları böyle kullanmak için iyi bir fikir olmadığı anlamına gelir. Bunun yerine, bunları ters projeksiyon matrisini kullanarak dünya koordinatlarına dönüştürün. – BlackCat

+0

Benim fikrim, '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '; Sanırım çoğu oyunda böyle yapıldı. Yaklaşımın işe yarayıp yaramadığından emin değilim. Biraz daha açıklar mısınız? – danijar

cevap

9

düzgün başıma bir Dördey döndürmek için nasıl bulundu. Anahtar, etrafta dönmek istediğim eksen için vektörler bulmaktı. Bunlar, eksen gerçek eksenin etrafında dönecek miktar olduğunda, eksen ve açıda kuaterniyonlar oluşturmak için kullanılır.

Aşağıdaki kod, neyle sonuçlandığımı gösterir. Aynı zamanda, kameranın dönmesine de yardımcı olur, bu da biraz zaman alabilir. Nadiren kuaternion rotasyonu hakkında bilgiler buldum yana

void Rotate(btVector3 Amount, float Sensitivity) 
{ 
    // fetch current rotation 
    btTransform transform = camera->getWorldTransform(); 
    btQuaternion rotation = transform.getRotation(); 

    // apply mouse sensitivity 
    Amount *= Sensitivity; 

    // create orientation vectors 
    btVector3 up(0, 1, 0); 
    btVector3 lookat = quatRotate(rotation, btVector3(0, 0, 1)); 
    btVector3 forward = btVector3(lookat.getX(), 0, lookat.getZ()).normalize(); 
    btVector3 side = btCross(up, forward); 

    // rotate camera with quaternions created from axis and angle 
    rotation = btQuaternion(up,  Amount.getY()) * rotation; 
    rotation = btQuaternion(side, Amount.getX()) * rotation; 
    rotation = btQuaternion(forward, Amount.getZ()) * rotation; 

    // set new rotation 
    transform.setRotation(rotation); 
    camera->setWorldTransform(transform); 
} 

, ben daha yukarıdaki kodu açıklayan biraz zaman harcarsınız.

getiriliyor ve rotasyon ayarı fizik motoru özeldir ve bu yüzden bu üzerinde fazla durmayacağım bu soruya ilgili değildir. Bir sonraki kısım, miktarı bir fare duyarlılığı ile çarpmak gerçekten açık olmalıdır. Yön vektörleri ile devam edelim.

  • up vektörü kendi uygulamanıza bağlıdır. En uygun şekilde, pozitif Y ekseni yukarı bakar, bu nedenle 0, 1, 0 ile sonuçlanırız.
  • lookat vektörü kameranın yönünü gösterir. Biz sadece kamera rotasyon kuaternion tarafından ileriye dönük bir birim vektör döndürmek. Yine, ileriye dönük vektör, sözleşmelerinize bağlıdır. Y ekseni doluysa, pozitif Z ekseni ileriye işaret edebilir, bu da 0, 0, 1'dur.
  • Bunu bir sonraki vektörle karıştırmayın. Kamera rotasyonuna gönderme yapan forward olarak adlandırılmıştır. Bu nedenle, lookat vektörünü zemine yansıtmamız gerekiyor. Bu durumda, sadece lookat vektörünü alıp yukarı işaret eden bileşeni görmezden geliyoruz. Düzenlilik için bu vektörü normalleştiririz.
  • side vektör noktaları, kamera yönünden sola doğru ayrılır. Bu nedenle hem up hem de forward vektörüne dik uzanır ve bunu hesaplamak için cross product'u kullanabiliriz.

Bu vektörler göz önüne alındığında, etrafındaki kamera dörtlüsünü doğru bir şekilde döndürebiliriz. Z, Y veya Z ile başladığınız, yine uygulamadan uygulamaya değişen bir kongre olan Euler angle sequence'a bağlıdır. Y X Z düzeninde uygulanacak döndürme yapmak istediğim için, aşağıdakileri yaparım.

  • İlk olarak, Y, rotasyon için bir miktar up eksen etrafında döndürme kamera. Bu yaw.
  • Ardından, sola doğru olan side eksenini X miktarı ile çevirin. Bu perde.
  • Son olarak, forward vektörünü döndürerek rulo uygulamak için Z miktarını döndürün.

Bu rotasyonları uygulamak için, geçerli kamera rotasyonuyla eksen ve açıyla oluşturulan kuaterniyonları çarpmamız gerekir. Son olarak, sonuçlanan kuaterniyonu fizik simülasyonunda vücuda uygularız.

0

Her ikisi de kendi sınırlamalarına sahip matrisler ve zift/yaw/roll, artık onları kullanmıyorum ama kuaterniyonlar yerine kullanıyorum. Görünüm vektörünü döndürürüm ve önce kamera vektörlerini, ardından döndürülen görüntü vektörüne göre görünüm matrisini yeniden hesaplar.

void Camera::rotateViewVector(glm::quat quat) { 

    glm::quat rotatedViewQuat; 

    quat = glm::normalize(quat); 
    m_viewVector = glm::normalize(m_viewVector); 

    glm::quat viewQuat(0.0f, 
     m_viewVector.x, 
     m_viewVector.y, 
     m_viewVector.z); 

    viewQuat = glm::normalize(viewQuat); 

    rotatedViewQuat = (quat * viewQuat) * glm::conjugate(quat); 
    rotatedViewQuat = glm::normalize(rotatedViewQuat); 

    m_viewVector = glm::normalize(glm::vec3(rotatedViewQuat.x, rotatedViewQuat.y, rotatedViewQuat.z)); 
    m_rightVector = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), m_viewVector)); 
    m_upVector = glm::normalize(glm::cross(m_viewVector, m_rightVector)); 
} 
İlgili konular