Zakładając, że masz na myśli kamerę obracającą się w oparciu o ruch myszy:
Jednym ze sposobów jego realizacji jest śledzenie położenia kamery i jej obrotu w przestrzeni. Współrzędne sferyczne są do tego wygodne, ponieważ można bezpośrednio przedstawić kąty.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
Kamera znajduje się w punkcie P zdefiniowanym przez m_theta, m_phi i m_radius. Możemy obracać i swobodnie poruszać się, gdziekolwiek chcemy, zmieniając te trzy wartości. Zawsze jednak patrzymy na m_target i obracamy się wokół niego. m_target to lokalne pochodzenie kuli. Możemy jednak swobodnie przenosić to pochodzenie w dowolne miejsce na świecie.
Istnieją trzy główne funkcje aparatu:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
W najprostszych postaciach Rotate () i Zoom () są trywialne. Wystarczy zmodyfikować odpowiednio m_theta, m_phi i m_radius:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
Panoramowanie jest nieco bardziej skomplikowane. Panoramowanie kamery definiuje się jako przesuwanie kamery w lewo / prawo i / lub góra / dół odpowiednio do bieżącego widoku kamery. Najłatwiejszym sposobem na to jest konwersja naszego obecnego widoku kamery ze współrzędnych sferycznych na współrzędne kartezjańskie. To daje nam do góry i odpowiednie wektory.
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);
}
Najpierw przekształcamy nasz sferyczny układ współrzędnych na kartezjański, aby uzyskać wektor wyglądu . Następnie wykonujemy iloczyn wektorowy z wektorem świat do góry , aby uzyskać właściwy wektor. Jest to wektor wskazujący bezpośrednio na prawo od widoku z kamery. Na koniec robimy kolejny krzyżowy produkt wektorowy, aby ustawić kamerę w górę .
Aby zakończyć przesuwanie, przesuwamy m_target wzdłuż wektorów w górę i w prawo .
Jedno z pytań, które możesz zadać, brzmi: po co cały czas konwertować między kartezjańskim i sferycznym (musisz także przekonwertować, aby utworzyć macierz Widoku).
Dobre pytanie. Ja też miałem to pytanie i starałem się używać wyłącznie kartezjańskich. Masz problemy z obrotami. Ponieważ operacje zmiennoprzecinkowe nie są dokładnie precyzyjne, wielokrotne obroty powodują kumulowanie się błędów, które odpowiadały kamerze powoli i niezamierzenie toczyły się.
W końcu utknąłem ze współrzędnymi sferycznymi. Aby przeciwdziałać dodatkowym obliczeniom, skończyłem buforowanie macierzy widoku i obliczam ją tylko wtedy, gdy kamera się porusza.
Ostatnim krokiem jest użycie tej klasy aparatu. Wystarczy wywołać odpowiednią funkcję członka w funkcjach MouseDown / Up / Scroll aplikacji:
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);
}
Zmienne m_camera * Factor są tylko czynnikami skalującymi, które zmieniają szybkość, z jaką kamera obraca się / przesuwa / przewija
Kod, który mam powyżej, jest uproszczoną pseudokodową wersją systemu kamer, który stworzyłem dla pobocznego projektu: camera.h i camera.cpp . Aparat próbuje naśladować system kamer Maya. Kod jest darmowy i open source, więc możesz go używać we własnym projekcie.