En supposant que vous voulez dire une caméra qui tourne en fonction du mouvement de la souris:
Une façon de l'implémenter est de garder une trace de la position de la caméra et de sa rotation dans l'espace. Les coordonnées sphériques sont pratiques pour cela, car vous pouvez représenter directement les angles.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
La caméra est située à P qui est défini par m_theta, m_phi et m_radius. Nous pouvons tourner et nous déplacer librement où nous voulons en modifiant ces trois valeurs. Cependant, nous regardons et tournons toujours autour de m_target. m_target est l'origine locale de la sphère. Cependant, nous sommes libres de déplacer cette origine où nous voulons dans l'espace mondial.
Il existe trois fonctions principales de l'appareil photo:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
Dans leurs formes les plus simples, Rotate () et Zoom () sont triviaux. Il suffit de modifier respectivement m_theta, m_phi et m_radius:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
Le panoramique est un peu plus compliqué. Un panoramique de la caméra est défini comme le déplacement de la caméra vers la gauche / droite et / ou vers le haut / bas par rapport à la vue de caméra actuelle. La façon la plus simple de le faire est de convertir notre vue de caméra actuelle des coordonnées sphériques en coordonnées cartésiennes. Cela nous donnera des vecteurs ascendants et droits .
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);
}
Donc, tout d'abord, nous convertissons notre système de coordonnées sphériques en cartésien pour obtenir notre vecteur de look . Ensuite, nous faisons le produit vectoriel croisé avec le vecteur monde vers le haut , afin d'obtenir un bon vecteur. Il s'agit d'un vecteur qui pointe directement à droite de la vue de la caméra. Enfin, nous faisons un autre vecteur produit croisé pour obtenir la caméra jusqu'à vecteur.
Pour terminer le panoramique, nous déplaçons m_target le long des vecteurs haut et droit .
Une question que vous pourriez vous poser est la suivante: pourquoi convertir entre cartésien et sphérique tout le temps (vous devrez également convertir pour créer la matrice de vue).
Bonne question. Moi aussi, j'ai eu cette question et j'ai essayé d'utiliser exclusivement la carte cartésienne. Vous vous retrouvez avec des problèmes de rotation. Étant donné que les opérations en virgule flottante ne sont pas exactement précises, plusieurs rotations finissent par accumuler des erreurs, qui correspondaient à la caméra lentement et roulaient accidentellement.
Donc, à la fin, je suis resté avec des coordonnées sphériques. Afin de contrer les calculs supplémentaires, j'ai fini par mettre en cache la matrice de vue et à la calculer uniquement lorsque la caméra se déplace.
La dernière étape consiste à utiliser cette classe Camera. Appelez simplement la fonction membre appropriée dans les fonctions MouseDown / Up / Scroll de votre application:
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);
}
Les variables de facteur m_camera * ne sont que des facteurs d'échelle qui changent la vitesse de rotation / panoramique / défilement de votre appareil photo
Le code que j'ai ci-dessus est une version pseudo-code simplifiée du système de caméra que j'ai fait pour un projet parallèle : camera.h et camera.cpp . La caméra essaie d'imiter le système de caméra Maya. Le code est gratuit et open source, alors n'hésitez pas à l'utiliser dans votre propre projet.