Bagaimana saya bisa mengorbit kamera tentang titik targetnya?

18

Saya sedang menggambar adegan di mana kamera bergerak bebas tentang alam semesta. Kelas kamera melacak titik pandang (atau melihat ), posisi kamera, dan vektor atas. Vektor / titik ini kemudian diteruskan ke gluLookAt.

Pan dan zoom hampir sepele untuk diterapkan. Namun, saya menemukan rotasi tentang tampilan pada titik menjadi lebih banyak masalah. Saya ingin menulis fungsi Camera.rotate yang mengambil 2 sudut, satu yang berputar naik / turun dan yang berputar kiri / kanan di sepanjang bola imajiner yang berpusat tentang tampilan pada titik.

Apakah ada cara mudah untuk melakukan ini?

Saya (secara singkat) telah membaca tentang angka empat, tetapi saya ingin melihat apakah ada solusi yang lebih mudah mengingat konstruksi adegan saya yang relatif sederhana.

Luke
sumber
Apakah Anda memiliki sesuatu di kotak alat Anda untuk memutar titik di sekitar titik asal, diberikan sumbu dan sudut?
sam hocevar
Tidak lain dari pemahaman longgar saya tentang Quaternions, tidak. Semakin saya melihat ini, saya pikir Quaternions mungkin jawabannya. Namun, saya tidak yakin bagaimana cara menghitung nilai sumbu x, y, dan z untuk digunakan dalam rumus Quaternion.
Lukas
Saya tidak akan memberi tahu Anda bahwa angka empat bukan cara untuk pergi. Mereka adalah solusi yang sangat baik untuk masalah Anda. Tetapi Anda akan membutuhkan kelas angka empat dan cara untuk berinteraksi dengan GL dan GLU, dan saya merasa bahwa Anda harus terlebih dahulu mencoba untuk mengenal matriks transformasi. Orang lain mungkin tidak setuju.
sam hocevar
pertimbangkan urutan apa yang Anda lakukan rotasi masuk menerapkan rotasi untuk pindah ke ruang dunia atau untuk pindah ke ruang kamera berbeda
Charlie

Jawaban:

25

Apa yang Anda minta disebut rotasi Arcball. Pertanyaan adalah solusi mudah hanya jika Anda mengerti cara kerjanya. Anda dapat mencapai hal yang sama tanpa angka empat.

Prasyarat

Apakah Anda tahu cara memutar objek secara umum? Katakanlah Anda memiliki objek pada awalnya. Apakah Anda tahu cara memutarnya (petunjuk: kalikan dengan beberapa matriks rotasi)? Jika ya, maka saya berasumsi Anda tahu apa yang akan terjadi jika Anda menerjemahkan objek terlebih dahulu dan kemudian memutarnya?

Anda harus tahu cara menghitung matriks rotasi dari sudut-sumbu (semudah pie, lihat segudang persamaan online, banyak dari mereka memberi Anda kode juga)

Larutan

  • Dapatkan kamera up dan kanan vektor. Perhatikan bahwa mereka harus dinormalisasi.
  • Dapatkan vektor dari titik fokus ke kamera (camPosition - Focus). Ini adalah vektor yang akan Anda putar. Sebut saja camFocusVector ini .
  • Putuskan seberapa banyak Anda ingin memutar dalam yaw / pitch sehubungan dengan kamera
  • Buat dua matriks rotasi. Matriks rotasi pertama akan menggunakan bagian atas kamera sebagai sumbu dan sudut yaw yang Anda putuskan. Matriks rotasi ke-2 akan menggunakan kanan kamera sebagai sumbu dan sudut pitch yang Anda putuskan.
  • Sekarang putar camFocusVector dengan matriks rotasi baru. Ini sekarang posisi baru kamera Anda relatif terhadap asal. Kami tentu saja, ingin itu relatif terhadap titik fokus ...
  • Tambahkan posisi titik fokus ke camFocusVector . Ini sekarang posisi baru kamera Anda. Terjemahkan kamera Anda sesuai.
  • Terakhir, minta kamera untuk fokus pada titik fokus dengan memanggil fungsi lookAt () Anda

Peringatan

Anda harus mencari case atau singularitas tertentu di mana kamera Anda akan berhenti bekerja. Tampak lurus ke bawah / atas misalnya. Saya akan membiarkan Anda mengetahui cara menghadapinya.

EDIT1: Cara menghitung ulang vektor ortonormal kamera

Anda sudah tahu arah kamera ((cameraPos - focusPoint) .normalisasi ()). Sekarang asumsikan bahwa kamera Anda adalah + Y (atau jika sumbu dunia Anda saat ini adalah ... itu terserah Anda). Sekarang cukup lintas arah dengan naik untuk mendapatkan yang benar . Selesai? Nggak! Vektor atas Anda tidak lagi ortogonal dengan dua lainnya. Untuk memperbaiki itu, silang tepat dengan arah dan Anda mendapatkan baru Anda up .

Perhatikan bahwa Gram-Schmidt adalah yang seharusnya digunakan untuk orthonormalize vektor.

Sekali lagi, perhatikan peringatan karena ini akan gagal untuk bekerja dalam beberapa kasus ( arahnya paralel ke atas misalnya).

Samaursa
sumber
Perhatikan bahwa vektor kanan dapat diperoleh dengan menggunakan normalize(up ^ camFocusVector)(atau kebalikannya jika kidal).
sam hocevar
Terlihat bagus sejauh ini, bekerja dengan indah untuk rotasi kiri / kanan (saya punya vektor naik sehingga mudah). Apa arti '^' dalam komentar Anda @SamHocevar? Apakah itu produk silang? Juga, bagaimana saya bisa menghitung ulang vektor atas setelah saya membuat terjemahan?
Lukas
@ Lukas: Periksa EDIT1 saya
Samaursa
1
@ Sasama Terima kasih banyak. Solusi Anda bekerja dengan sempurna, dan saya belajar banyak dalam prosesnya!
Lukas
2
ini jawaban yang SANGAT BAIK, terima kasih banyak atas penjelasannya. Dalam kasus saya, saya ingin kamera hanya berputar tentang titik target pada bidang XY, dan setelah melakukan semua perhitungan, saya selalu mengatur cameraRight.z ke 0 dan kemudian menghitung vektor cameraUp. Ini memberi efek yang diinginkan. Pikirkan saja berbagi
codemonkey
1

Yang Anda butuhkan adalah kamera ArcBall yang khas, yang pada dasarnya adalah kamera yang menyimpan lokasi target dan memungkinkan Anda untuk memindahkan kamera dengan cara "bulat" di sekitar target itu.

Ada dalam XNA tetapi IIRC Saya telah menggunakan implementasi ini sebelumnya, dan itu bekerja dengan cukup baik:

http://roy-t.nl/index.php/2010/02/21/xna-simple-arcballcamera/

David Gouveia
sumber
Implementasi itu tampaknya hanya bergerak langsung di sepanjang vektor kanan, yang akan memperkirakan bola busur untuk nilai-nilai kecil jumlahnya . Dia juga menggerakkan titik LookAt, di mana saya ingin memindahkan kamera (dekat, tetapi agak berbeda). Saya percaya Samaursa telah menyediakan cara lengkap yang paling sederhana untuk mencapai ini.
Lukas
Terima kasih atas tanggapan Anda. Saya harus mengakui bahwa saya menggunakan implementasi ini sedikit sebagai "kotak hitam" tetapi saya tidak melihat adanya masalah. Untuk memperjelas apakah Anda mungkin berbicara tentang metode MoveCameraRight / MoveCameraForward? Metode-metode itu ditambahkan untuk menggeser kamera, tetapi bukan bagian dari antarmuka Arcball. Jika Anda ingin memutar kamera di sekitar target, Anda cukup mengubah properti Yaw atau Pitch.
David Gouveia
Maaf, Anda benar, itu adalah metode panning. Saya tidak memperhatikan bagaimana dia mengatur flag kotor untuk matrix ketika yaw and pitch diubah.
Lukas
0

Inilah kode saya untuk berputar di suatu titik, mendapati diri saya sering menggunakannya kembali.

float distance;      // Straight line distance between the camera and look at point

// Calculate the camera position using the distance and angles
float camX = distance * -sinf(camAngleX*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));
float camY = distance * -sinf((camAngleY)*(M_PI/180));
float camZ = -distance * cosf((camAngleX)*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));

// Set the camera position and lookat point
gluLookAt(camX,camY,camZ,   // Camera position
          0.0, 0.0, 0.0,    // Look at point
          0.0, 1.0, 0.0);   // Up vector
Stephen Tierney
sumber
1
Pada dasarnya itulah yang saya lakukan pada awalnya. Ada banyak masalah dengan melakukannya dengan cara ini (setidaknya untuk saya). Pada dasarnya implementasi ini hanya berputar sekitar 2 sumbu tetap. Katakanlah Anda memutar sampai hampir ke kutub utara . Kemudian putar ke kanan . Anda akan menemukan diri Anda berputar dalam lingkaran kecil daripada mengikuti vektor kanan kamera di seluruh dunia .
Lukas
Sekarang setelah Anda menyebutkannya, saya kira ada dua cara berbeda untuk melihat masalahnya. Dalam aplikasi saya, saya menggunakan kamera ArcBall untuk memutar di sekitar pulau target di laut, dan jika saya menggunakan 3 sumbu kebebasan itu akan terlihat jelas salah (seperti melihat pulau terbalik atau menyamping).
David Gouveia
Bagaimana cara mendapatkan sudut kamera di sini?
rafvasq
0

Algoritma yang sangat sederhana untuk mencapai ini sangat mengagumkan:

Menjadi P titik pusat tentang Anda ingin memutar (titik "lihat" atau "target"):

translate(-P)

rotate horizontal
rotate vertical

translate(P)

Saya menggunakannya dan itu bagus.

Sumber ditemukan di stackoverflow situs saudara: /programming/287655/opengl-rotating-a-camera-around-a-point

diosney
sumber