Asumsikan yang Anda maksudkan adalah kamera yang berputar berdasarkan pergerakan mouse:
Salah satu cara untuk mengimplementasikannya adalah melacak posisi kamera dan rotasinya di ruang angkasa. Koordinat bola kebetulan cocok untuk ini, karena Anda dapat mewakili sudut secara langsung.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
Kamera terletak di P yang didefinisikan oleh m_theta, m_phi, dan m_radius. Kita dapat memutar dan bergerak dengan bebas ke mana pun kita inginkan dengan mengubah ketiga nilai tersebut. Namun, kami selalu melihat, dan memutar, m_target. m_target adalah asal usul bola. Namun, kita bebas untuk memindahkan asal ini ke mana pun kita inginkan di ruang dunia.
Ada tiga fungsi kamera utama:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
Dalam bentuknya yang paling sederhana, Putar () dan Zoom () sepele. Hanya memodifikasi m_theta, m_phi, dan m_radius masing-masing:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
Panning sedikit lebih rumit. Pan kamera didefinisikan sebagai menggerakkan kamera ke kiri / kanan dan / atau atas / bawah masing-masing ke tampilan kamera saat ini. Cara termudah yang dapat kita lakukan ini adalah mengubah tampilan kamera kita saat ini dari koordinat bola ke koordinat kartesius. Ini akan memberi kita vektor ke atas dan kanan .
void Camera::Pan(float dx, float dy) {
float3 look = normalize(ToCartesian());
float3 worldUp = float3(0.0f, 1.0f, 0.0f, 0.0f);
float3 right = cross(look, worldUp);
float3 up = cross(look, right);
m_target = m_target + (right * dx) + (up * dy);
}
inline float3 ToCartesian() {
float x = m_radius * sinf(m_phi) * sinf(m_theta);
float y = m_radius * cosf(m_phi);
float z = m_radius * sinf(m_phi) * cosf(m_theta);
float w = 1.0f;
return float3(x, y, z, w);
}
Jadi, pertama, kita mengonversi sistem koordinat bola kita menjadi cartesian untuk mendapatkan vektor tampilan kita . Berikutnya, kita lakukan vektor lintas produk dengan dunia atas vektor, untuk mendapatkan hak vektor. Ini adalah vektor yang menunjuk langsung ke kanan dari tampilan kamera. Terakhir, kita lakukan vektor lain silang produk untuk mendapatkan kamera up vektor.
Untuk menyelesaikan panci, kami memindahkan m_target di sepanjang vektor ke atas dan kanan .
Satu pertanyaan yang mungkin Anda tanyakan adalah: Mengapa mengkonversi antara kartesius dan bola sepanjang waktu (Anda juga harus mengonversi untuk membuat matriks View).
Pertanyaan bagus. Saya juga punya pertanyaan ini dan mencoba menggunakan kartesian secara eksklusif. Anda berakhir dengan masalah dengan rotasi. Karena operasi floating point tidak tepat tepat, beberapa rotasi berakhir dengan akumulasi kesalahan, yang terkait dengan kamera secara perlahan, dan bergulir secara tidak sengaja.
Jadi, pada akhirnya, saya terjebak dengan koordinat bola. Untuk melawan perhitungan ekstra, saya akhirnya melakukan caching view matrix, dan hanya menghitungnya saat kamera bergerak.
Langkah terakhir adalah menggunakan kelas Kamera ini. Panggil saja fungsi anggota yang sesuai di dalam fungsi MouseDown / Atas / Gulir aplikasi Anda:
void MouseDown(WPARAM buttonState, int x, int y) {
m_mouseLastPos.x = x;
m_mouseLastPos.y = y;
SetCapture(m_hwnd);
}
void MouseUp(WPARAM buttonState, int x, int y) {
ReleaseCapture();
}
void MouseMove(WPARAM buttonState, int x, int y) {
if ((buttonState & MK_LBUTTON) != 0) {
if (GetKeyState(VK_MENU) & 0x8000) {
// Calculate the new phi and theta based on mouse position relative to where the user clicked
float dPhi = ((float)(m_mouseLastPos.y - y) / 300);
float dTheta = ((float)(m_mouseLastPos.x - x) / 300);
m_camera.Rotate(-dTheta, dPhi);
}
} else if ((buttonState & MK_MBUTTON) != 0) {
if (GetKeyState(VK_MENU) & 0x8000) {
float dx = ((float)(m_mouseLastPos.x - x));
float dy = ((float)(m_mouseLastPos.y - y));
m_camera.Pan(-dx * m_cameraPanFactor, dy * m_cameraPanFactor);
}
}
m_mouseLastPos.x = x;
m_mouseLastPos.y = y;
}
void MouseWheel(int zDelta) {
// Make each wheel dedent correspond to a size based on the scene
m_camera.Zoom((float)zDelta * m_cameraScrollFactor);
}
Variabel faktor m_camera * hanyalah faktor skala yang mengubah seberapa cepat kamera Anda memutar / menggeser / menggulir
Kode yang saya miliki di atas adalah versi kode semu yang disederhanakan dari sistem kamera yang saya buat untuk proyek sampingan: camera.h dan camera.cpp . Kamera mencoba meniru sistem kamera Maya. Kode ini gratis dan open source, jadi silakan menggunakannya dalam proyek Anda sendiri.