Supondo que você queira dizer uma câmera que gira com base no movimento do mouse:
Uma maneira de implementá-lo é acompanhar a posição da câmera e sua rotação no espaço. As coordenadas esféricas são convenientes para isso, pois você pode representar os ângulos diretamente.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
A câmera está localizada em P, definida por m_theta, m_phi e m_radius. Podemos girar e mover-nos livremente para onde quisermos, alterando esses três valores. No entanto, sempre olhamos e giramos em torno de m_target. m_target é a origem local da esfera. No entanto, somos livres para mudar essa origem para onde quisermos no espaço do mundo.
Existem três funções principais da câmera:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
Em suas formas mais simples, Rotate () e Zoom () são triviais. Basta modificar m_theta, m_phi e m_radius, respectivamente:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
O movimento panorâmico é um pouco mais complicado. Um pan da câmera é definido como mover a câmera para a esquerda / direita e / ou para cima / para baixo, respectivamente, para a visualização atual da câmera. A maneira mais fácil de conseguir isso é converter nossa visão atual da câmera de coordenadas esféricas em coordenadas cartesianas. Isso nos dará um up e certos vetores.
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);
}
Então, primeiro, convertemos nosso sistema de coordenadas esféricas em cartesiano para obter nosso vetor de aparência . Em seguida, fazemos o produto cruzado do vetor com o mundo até vetor, a fim de obter um certo vetor. Este é um vetor que aponta diretamente para a direita da visualização da câmera. Por fim, fazemos outro produto cruzado de vetor para obter a câmera de vetor.
Para finalizar o pan, movemos m_target pelos vetores para cima e para a direita .
Uma pergunta que você pode estar perguntando é: Por que converter entre cartesiano e esférico o tempo todo (você também precisará converter para criar a matriz View).
Boa pergunta. Eu também tive essa pergunta e tentei usar exclusivamente cartesiano. Você acaba com problemas com rotações. Como as operações de ponto flutuante não são exatamente precisas, várias rotações acabam acumulando erros, que correspondiam à câmera lenta e involuntariamente.
Então, no final, eu fiquei com coordenadas esféricas. A fim de combater os cálculos extras, acabei armazenando em cache a matriz de visualização e só a calculo quando a câmera se move.
O último passo é usar esta classe de câmera. Basta chamar a função de membro apropriada nas funções MouseDown / Up / Scroll do seu aplicativo:
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);
}
As variáveis m_camera * Factor são apenas fatores de escala que alteram a rapidez com que sua câmera gira / desloca / rola
O código que eu tenho acima é uma versão pseudo-código simplificado do sistema de câmera que eu fiz para um projeto paralelo: camera.h e camera.cpp . A câmera tenta imitar o sistema de câmera Maya. O código é gratuito e de código aberto, portanto, fique à vontade para usá-lo em seu próprio projeto.