Suponiendo que se refiere a una cámara que gira según el movimiento del mouse:
Una forma de implementarlo es hacer un seguimiento de la posición de la cámara y su rotación en el espacio. Las coordenadas esféricas resultan convenientes para esto, ya que puede representar los ángulos directamente.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
La cámara está ubicada en P, que está definida por m_theta, m_phi y m_radius. Podemos rotar y movernos libremente donde queramos cambiando esos tres valores. Sin embargo, siempre miramos y giramos alrededor de m_target. m_target es el origen local de la esfera. Sin embargo, somos libres de mover este origen a donde queramos en el espacio mundial.
Hay tres funciones principales de la cámara:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
En sus formas más simples, Rotate () y Zoom () son triviales. El solo modifica m_theta, m_phi y m_radius respectivamente:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
La panorámica es un poco más complicada. Una panorámica de la cámara se define como mover la cámara hacia la izquierda / derecha y / o arriba / abajo, respectivamente, a la vista de la cámara actual. La forma más fácil de lograr esto es convertir nuestra vista actual de la cámara de coordenadas esféricas a coordenadas cartesianas. Esto nos dará un vector ascendente y correcto .
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);
}
Entonces, primero, convertimos nuestro sistema de coordenadas esféricas a cartesiano para obtener nuestro vector de aspecto . A continuación, se hace el producto vectorial con el mundo arriba vector, con el fin de obtener un derecho de vectores. Este es un vector que apunta directamente a la derecha de la vista de la cámara. Por último, hacemos otro producto vectorial para conseguir la cámara hasta vectorial.
Para terminar la panorámica, movemos m_target a lo largo de los vectores arriba y derecha .
Una pregunta que podría estar haciendo es: ¿Por qué convertir entre cartesiano y esférico todo el tiempo (también tendrá que convertir para crear la matriz de Vista).
Buena pregunta. Yo también tuve esta pregunta y traté de usar exclusivamente cartesian. Terminas con problemas con las rotaciones. Dado que las operaciones de coma flotante no son exactamente precisas, las rotaciones múltiples terminan acumulando errores, que correspondieron a la cámara lentamente y sin querer rodando.
Entonces, al final, me quedé con las coordenadas esféricas. Para contrarrestar los cálculos adicionales, terminé almacenando en caché la matriz de vista y solo la calculé cuando la cámara se mueve.
El último paso es usar esta clase de cámara. Simplemente llame a la función de miembro apropiada dentro de las funciones MouseDown / Up / Scroll de su aplicación:
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);
}
Las variables m_camera * Factor son solo factores de escala que cambian la rapidez con la que la cámara gira / gira / desplaza
El código que tengo arriba es una versión simplificada de pseudocódigo del sistema de cámara que hice para un proyecto paralelo: camera.h y camera.cpp . La cámara intenta imitar el sistema de cámara Maya. El código es gratuito y de código abierto, así que siéntase libre de usarlo en su propio proyecto.