2013-02-16 29 views
6

Harita için tüm gezegeni kullanan bir oyun yapıyorum. Küresel gezegen using this technique'u düğümledim ve şimdi kamera kontrollerine ekliyorum. Fotoğraf Makinesini Noktaya Döndürme

Küre 1 - -1 boyutlarındadır, bu nedenle küre üzerindeki her nokta da normalleştirilmiş bir vektördür. Herhangi bir zamanda, küre oluşturan altıgen fayanslardan biri 'seçilmiş' karodur. Oynatıcı daha sonra d-pad'i kullanarak seçimi komşu karolara taşıyabilir. Aynı zamanda kamerayı bağımsız olarak analog çubuk

kullanarak döndürebilirler. Seçilen karo ve kamerayla ilgili iki şey yapmam gerek. İlk olarak, seçimi kameraya en yakın olan döşemeye geçirmem gerekiyor. İkincisi, kamerayı vurgulanmış çini

üzerinde merkezlemem gerekiyor. Küre orijin üzerinde oturuyor ve kamera noktada (0,0,1) oturuyor. Grafik motoru sadece kamerayı X ve Y eksenleri etrafında döndürmemize izin veriyor, böylece ilk problemi çözmek için, noktayı bulmak için x ve daha sonra y eksenlerini (0,0,1) döndürmek için kuaterniyonları kullanıyorum.

private Quaternion quat = new Quaternion(0,0,0,0); 
    private double[] output = new double[4]; 
    private double[] cam = new double[3]; 

    private double camX = 0; 
    private double camY = 0; 
    private double camZ = 1; 


    private double[] getCamPosition(){ 

     quat.setAxisAngle(1, 0, 0, Math.toRadians(-graphicsEngine.getRotationX())); 
     quat.RotateVector(camX, camY, camZ, output);    
     cam[0] = output[0]; 
     cam[1] = output[1]; 
     cam[2] = output[2]; 

     quat.setAxisAngle(0, 1, 0, Math.toRadians(-graphicsEngine.getRotationY())); 
     quat.RotateVector(cam[0], cam[1], cam[2], output);   
     cam[0] = output[0]; 
     cam[1] = output[1]; 
     cam[2] = output[2]; 

     return cam; 
    } 

sonra her karo ağırlık merkezi ve kamera pozisyonu arasındaki mesafeleri karşılaştırmak ve yeni seçilen kiremit olmak en yakın olan döşemeyi almak: kamera 3D uzay. Ancak, ikinci problemi çözmek için tersini yapmak istiyorum. Centroid'i (zaten normalleştirilmiş bir vektör biçiminde) alıp, kameranın ortalanması için gerekli olan X etrafında dönmeyi ve dönmeyi öğrenmek istiyorum.

Şu an Fotoğraf makinesini (0,0,1) konumuna döndürdüğümde, X ekseni ve Y eksenindeki açı (0,0,1) ile merkez arasında dönerek kamerayı ikinci kez döndürmek için:

private double[] outputArray = new double[2]; 

/** 
* Cam is always (0,0,1) 
*/ 
public void centreOnSelected(double camX, double camY, double camZ){   

    selectedTile.getCentroidAngles(outputArray); 

    outputArray[0] -= Math.atan2(camZ, camY); 
    outputArray[1] -= Math.atan2(camX, camZ); 

    // this determines if the centroid is pointing away from the camera 
    // I.e. is on the far side of the sphere to the camera point (0,0,1) 
    if(!selected.getCentroidDirectionY(camX, camZ)){ 
     outputArray[0] = -Math.PI - outputArray[0];   
    } 

    graphicsEngine.rotateCam(Math.toDegrees(outputArray[0]), Math.toDegrees(outputArray[1])); 


} 

ve selected (kiremit sınıfı) içinde

void getCentroidAngles(double[] outputArray){ 
    outputArray[0] = Math.atan2(centroidZ, centroidY); 
    outputArray[1] = Math.atan2(centroidX, centroidZ); 

} 

sorun şudur çalışmaz (x ekseni her zaman dışarıda görünür), ve ben açıları almak ve dönen

yapıyor matematik ile yapmak için eminim Not: grafik motoru ilk önce etrafında döner Daha sonra Y etrafında X ekseni:

 gl.glRotatef(mRotateX, 1, 0, 0); 
     gl.glRotatef(mRotateY, 0, 1, 0); 

sentroidler hepsi doğru yerde olduğunu ve kamera kesinlikle doğru miktarlarda tarafından döner, bu yüzden sorun grafik motoru ile değil eminim. Geri (0,0,1) için bu kontrol ettim aynı zamanda kameranın yeniden konumlandırma değil

Ben de sorunu göstermek için bir video yaptık program sayesinde adım atarak çalışır:

http://www.youtube.com/watch?v=Uvka7ifZMlE

Bu, birkaç gün boyunca beni rahatsız ediyor, bu yüzden bu düzeltmeye yardımcı olacak herhangi bir yardım çok takdir edilecektir!

Teşekkür James

cevap

2

Ne yazık ki tamamen burada neler olduğunu anlamıyorum ve tam sunamadığım, ama en azından bakmak için bazı sorunları işaret edebilir.

GlRotatef'i hiç kullanmadım, ancak burada dönüşümlerin sırası ve işareti hakkında biraz kafam karışmış durumda - örneğin, glRotatef çağrılarınızın sırasına göre ilk önce x rotasyonunu gerçekten yapıyor musunuz? İlk birinde (centroidY, centroidZ) demek istedi

Neyse, sorunun en azından bir kısmını burada, bu denklemlerin

Öncelikle
outputArray[0] = Math.atan2(centroidZ, centroidY); 
outputArray[1] = Math.atan2(centroidX, centroidZ); 

geliyor? Daha ciddi olarak, burada aldığınız açıları, (0,0,1)'u merkezinize veya tersine taşıyacak bir rotasyon oluşturmak için kullanılamaz. Örneğin, centroid vektörünüzü (0,0,1)'a döndürmek istediğinizi varsayalım. 2 rotasyonunuzun her biri, tek bir aksamı sıfırlamak için tek bir eksen etrafında döndürmek için kullanılabilir. Örneğin, uygun bir işaretin x ekseni etrafında outputArray[0] tarafından bir rotasyon, y bileşenini sıfıra ayarlayacaktır (argümanların atan2'a değiştirildiği varsayılarak). Alternatif olarak, y ekseni hakkında doğru işaretin outputArray[1] tarafından bir döndürme, x bileşenini 0'a ayarlayabilir. Ancak, y bileşenini 0'a ayarlamak için önce x dönüşünü yaptıktan sonra, santroid vektörünü değiştirir - şimdi y ekseni etrafında dönüş x bileşenini 0 olarak ayarlayacağınız, outputArray[1] tarafından artık açıklanmamaktadır.

Bu şeyler için uygun formüller, her zaman bir açı için atan2 ve diğeri için acos veya asin'a sahiptir. Örneğin (x,y,z) üzerine vektör (1,0,0) taşıyacak etkin bir dönüş için açılar Eğer Bu açılar etrafında rotasyonları tarif (eğer

first_angle_around_x = atan2(y, z) 
second_angle_around_y = -asin(x) 

kullanacağı (1,0,0) üzerine (x,y,z) taşımak için

first_angle_around_x = -asin(y) 
second_angle_around_y = atan2(x, z) 

kullanmak isterseniz eksen "sizi gözünüze soktuğunda" saat yönünün tersine x, y eksenleri.)

Başka bir sorun burada

outputArray[0] -= Math.atan2(camZ, camY); 
outputArray[1] -= Math.atan2(camX, camZ); 

Bunun gibi açıları çıkarma, yalnızca tek bir eksen etrafındaki dönüşler için çalışır. Farklı eksenler etrafındaki rotasyonların dışında birleşik dönüşümler oluşturduğunuzda ilişki çok daha karmaşık hale gelir - matrisler ve kuaterniyonlar bu yüzden işe yarar. Bu kod, camX-Z girişlerinin metottan önceki yorum tarafından önerildiği gibi gereksiz olduğunu tahmin edebilir (Z ve Y bileşenlerinin şu an yuvarlak olmasına rağmen, burada sıfır olmayan bir sonuç verebilirler) Bahsettiğim ilk denklemlerde "yanlış" bir yol olmalarını telafi etmek, bu kasıtlı olup olmadığından emin değilim).

Ayrıca, kamerayı seçilen kutuya taşıdığınız yolla ilgili temel bir sorun var, ancak aslında bir sorun olup olmadığı konusunda biraz öznel. X ve y eksenleri etrafında sadece rotasyon yaptığınız için, gezegeninizdeki her nokta için benzersiz bir kamera oryantasyonuna sahip olursunuz. Sorun şu ki, böyle bir yönelimi sürekli olarak seçmenin bir yolu yok - bu, gezegendeki bir vektör alanının, her noktada vektörün, kamera o noktanın üzerinde olduğunda x yönünü gösteren bir birim vektör olduğunu hayal ettiğini görmek. Bu alan Hairy Ball Theorem tarafından sürekli olamaz. Pratikte bunun anlamı, gezegende, kamera konumunun küçük bir ayarının yapılmasının, gezegen tekerleğinin ekranda 180 dereceye kadar çıkmasını sağlayacağı bir nokta olacaktır. Bundan kaçınmak isterseniz, rotasyon miktarını en aza indirmek için, geçerli kamera pozisyonunda bulunan yönlendirmeyi seçebilirsiniz.Bu, örneğin, kameranın oyununuzda arzu edilmeyen kapalı bir döngüde hareket etmesi durumunda, ekranın ekranda "yuvarlandığını" göstermesi anlamına gelir. Ayrıca, motorunuzun her 3 eksende de dönüş yapabilmesini gerektirir.

+0

İlginç, teşekkürler! Çevremizdeki tekerleği anlıyorum ama hiçbir zaman bir ismin olmadığını anladım (daha az, tüylü top teoremi kadar komikti). Bu wheeling davranışı, oynadığım bilgisayar oyunlarında nadir değildir ve muhtemelen oyunumu oynarken küçük bir grafik rahatsızlığı olarak hizmet edecektir. Öyle görünüyor ki, kameranın merkezileştirilmesini/dönmesini beklemek gibi –

İlgili konular