Angenommen, Sie meinen eine Kamera, die sich aufgrund der Mausbewegung dreht:
Eine Möglichkeit zur Implementierung besteht darin, die Kameraposition und ihre Drehung im Raum zu verfolgen. Hierfür bieten sich sphärische Koordinaten an, da Sie die Winkel direkt darstellen können.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
Die Kamera befindet sich bei P, das durch m_theta, m_phi und m_radius definiert ist. Wir können uns frei drehen und bewegen, wo immer wir wollen, indem wir diese drei Werte ändern. Wir schauen uns jedoch immer m_target an und drehen es. m_target ist der lokale Ursprung der Kugel. Es steht uns jedoch frei, diesen Ursprung im Weltraum zu bewegen, wo immer wir wollen.
Es gibt drei Hauptfunktionen der Kamera:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
In ihrer einfachsten Form sind Rotate () und Zoom () trivial. Die beiden Modifikationen m_theta, m_phi und m_radius lauten:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
Schwenken ist etwas komplizierter. Ein Kameraschwenk ist definiert als Bewegen der Kamera nach links / rechts und / oder nach oben / unten in Bezug auf die aktuelle Kameraansicht. Am einfachsten können wir dies erreichen, indem wir unsere aktuelle Kameraansicht von sphärischen Koordinaten in kartesische Koordinaten konvertieren. Dies gibt uns eine nach oben und rechts Vektoren.
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);
}
Also, zunächst wandeln wir unser sphärisches Koordinatensystem kartesisch zu unserem bekommen Look Vektor. Als nächstes machen wir das Vektorkreuzprodukt mit dem Welt- Up- Vektor, um einen richtigen Vektor zu erhalten. Dies ist ein Vektor, der direkt rechts von der Kameraansicht zeigt. Zuletzt machen wir ein anderes Vektor-Kreuzprodukt, um den Vektor der Kamera zu erzeugen.
Um die Pfanne zu beenden, wir bewegen m_target entlang der nach oben und rechts Vektoren.
Eine Frage, die Sie sich möglicherweise stellen, lautet: Warum immer zwischen kartesisch und sphärisch konvertieren? (Sie müssen auch konvertieren, um die View-Matrix zu erstellen.)
Gute Frage. Auch ich hatte diese Frage und versuchte ausschließlich kartesisch zu sprechen. Sie haben Probleme mit Rotationen. Da Gleitkommaoperationen nicht exakt sind, häufen sich bei mehreren Umdrehungen Fehler an, die der Kamera langsam entsprachen und ungewollt abrollen.
Also blieb ich am Ende bei sphärischen Koordinaten. Um den zusätzlichen Berechnungen entgegenzuwirken, habe ich die Ansichtsmatrix zwischengespeichert und erst berechnet, wenn sich die Kamera bewegt.
Der letzte Schritt ist die Verwendung dieser Kamera-Klasse. Rufen Sie einfach die entsprechende Member-Funktion in den MouseDown / Up / Scroll-Funktionen Ihrer App auf:
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);
}
Die m_camera * -Faktorvariablen sind lediglich Skalierungsfaktoren, die ändern, wie schnell sich Ihre Kamera dreht / schwenkt / rollt
Der Code, den ich oben habe, ist eine vereinfachte Pseudocode-Version des Kamerasystems, das ich für ein Nebenprojekt erstellt habe: camera.h und camera.cpp . Die Kamera versucht das Maya-Kamerasystem zu imitieren. Der Code ist kostenlos und Open Source. Sie können ihn also auch in Ihrem eigenen Projekt verwenden.