Giả sử bạn có nghĩa là một camera xoay dựa trên chuyển động của chuột:
Một cách để thực hiện nó là theo dõi vị trí camera và góc quay của nó trong không gian. Các tọa độ hình cầu xảy ra thuận tiện cho việc này, vì bạn có thể biểu diễn các góc trực tiếp.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
Máy ảnh được đặt tại P được xác định bởi m_theta, m_phi và m_radius. Chúng ta có thể xoay và di chuyển tự do bất cứ nơi nào chúng ta muốn bằng cách thay đổi ba giá trị đó. Tuy nhiên, chúng tôi luôn nhìn và xoay quanh, m_target. m_target là nguồn gốc địa phương của hình cầu. Tuy nhiên, chúng tôi có thể tự do di chuyển nguồn gốc này bất cứ nơi nào chúng tôi muốn trong không gian thế giới.
Có ba chức năng camera chính:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
Trong các hình thức đơn giản nhất của họ, Rotate () và Zoom () là tầm thường. Việc sửa đổi lần lượt m_theta, m_phi và m_radius:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
Panning phức tạp hơn một chút. Một pan camera được định nghĩa là di chuyển camera sang trái / phải và / hoặc lên / xuống tương ứng với chế độ xem camera hiện tại. Cách dễ nhất chúng ta có thể thực hiện điều này là chuyển đổi chế độ xem camera hiện tại của chúng ta từ tọa độ hình cầu sang tọa độ cartesian. Điều này sẽ cho chúng ta một vectơ lên và phải .
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);
}
Vì vậy, trước tiên, chúng tôi chuyển đổi hệ tọa độ hình cầu của chúng tôi sang cartesian để có được vector nhìn của chúng tôi . Tiếp theo, chúng tôi làm sản phẩm chéo vector với thế giới lên vector, để có được một ngay vector. Đây là một vectơ chỉ trực tiếp bên phải của chế độ xem camera. Cuối cùng, chúng tôi làm một sản phẩm chéo vector khác để đưa máy ảnh lên vector.
Để hoàn thành pan, chúng tôi di chuyển m_target dọc theo vectơ lên và phải .
Một câu hỏi bạn có thể hỏi là: Tại sao phải chuyển đổi giữa cartesian và hình cầu mọi lúc (bạn cũng sẽ phải chuyển đổi để tạo ma trận View).
Câu hỏi hay. Tôi cũng có câu hỏi này và đã cố gắng sử dụng độc quyền cartesian. Bạn kết thúc với các vấn đề với luân chuyển. Do các hoạt động của dấu phẩy động không chính xác chính xác, nhiều lần quay cuối cùng sẽ tích lũy các lỗi, tương ứng với máy ảnh một cách chậm chạp và vô tình lăn.
Vì vậy, cuối cùng, tôi bị mắc kẹt với tọa độ hình cầu. Để chống lại các tính toán bổ sung, cuối cùng tôi đã lưu vào bộ đệm ma trận khung nhìn và chỉ tính toán khi máy ảnh di chuyển.
Bước cuối cùng là sử dụng lớp Camera này. Chỉ cần gọi chức năng thành viên phù hợp bên trong các chức năng MouseDown / Up / Scroll của ứng dụng của bạ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);
}
Các biến m_camera * Các yếu tố chỉ là các yếu tố tỷ lệ thay đổi tốc độ quay / pans / cuộn của máy ảnh của bạn
Mã tôi có ở trên là phiên bản mã giả đơn giản hóa của hệ thống camera tôi đã tạo cho một dự án phụ: camera.h và camera.cpp . Máy ảnh cố gắng bắt chước hệ thống camera Maya. Mã này là mã nguồn mở và miễn phí, vì vậy hãy sử dụng nó trong dự án của riêng bạn.