Supponendo che intendi una videocamera che ruota in base al movimento del mouse:
Un modo per implementarlo è tenere traccia della posizione della telecamera e della sua rotazione nello spazio. Le coordinate sferiche sono utili per questo, poiché puoi rappresentare direttamente gli angoli.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
La fotocamera si trova in P, che è definita da m_theta, m_phi e m_radius. Possiamo ruotare e muoverci liberamente dove vogliamo cambiando questi tre valori. Tuttavia, guardiamo sempre e ruotiamo intorno a m_target. m_target è l'origine locale della sfera. Tuttavia, siamo liberi di spostare questa origine ovunque desideriamo nello spazio mondiale.
Esistono tre funzioni principali della fotocamera:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
Nelle loro forme più semplici, Rotate () e Zoom () sono banali. Il giusto modifica rispettivamente m_theta, m_phi e m_radius:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
La panoramica è un po 'più complicata. Una panoramica della videocamera è definita come lo spostamento della videocamera verso sinistra / destra e / o verso l'alto / verso il basso rispetto alla vista corrente della videocamera. Il modo più semplice per raggiungere questo obiettivo è convertire la nostra attuale vista della telecamera da coordinate sferiche a coordinate cartesiane. Questo ci darà un up e di destra vettori.
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);
}
Quindi, in primo luogo, convertiamo il nostro sistema di coordinate sferiche in cartesiano per ottenere il nostro aspetto vettoriale. Successivamente, realizziamo il vettore incrociato con il vettore world up , al fine di ottenere un vettore giusto . Questo è un vettore che punta direttamente a destra della vista della telecamera. Infine, facciamo un altro prodotto vettoriale incrociato per ottenere la fotocamera su vettore.
Per finire la panoramica, spostiamo m_target lungo i vettori su e destra .
Una domanda che potresti porci è: perché convertire continuamente tra cartesiano e sferico (dovrai anche convertire per creare la matrice Visualizza).
Buona domanda. Anch'io avevo questa domanda e ho provato ad usare esclusivamente cartesiano. Si finiscono con problemi con le rotazioni. Poiché le operazioni in virgola mobile non sono esattamente precise, più rotazioni finiscono per accumulare errori, che corrispondevano lentamente alla telecamera e rotolavano involontariamente.
Quindi, alla fine, mi sono bloccato con coordinate sferiche. Al fine di contrastare i calcoli aggiuntivi, ho finito per memorizzare nella cache la matrice di visualizzazione e calcolarla solo quando la telecamera si sposta.
L'ultimo passo è usare questa classe Camera. Basta chiamare la funzione membro appropriata all'interno delle funzioni MouseDown / Su / Scorrimento della tua app:
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);
}
Le variabili del fattore m_camera * sono solo fattori di scala che cambiano la velocità di rotazione / panoramica / scorrimento della videocamera
Il codice che ho sopra è una versione semplificata del pseudo-codice del sistema di telecamere che ho realizzato per un progetto laterale: camera.h e camera.cpp . La fotocamera tenta di imitare il sistema di telecamere Maya. Il codice è gratuito e open source, quindi sentiti libero di usarlo nel tuo progetto.