Предполагая, что вы имеете в виду камеру, которая вращается в зависимости от движения мыши:
Одним из способов его реализации является отслеживание положения камеры и ее вращения в пространстве. Сферические координаты удобны для этого, так как вы можете представлять углы напрямую.
float m_theta;
float m_phi;
float m_radius;
float3 m_target;
Камера расположена в P, который определяется m_theta, m_phi и m_radius. Мы можем свободно вращаться и двигаться в любом месте, изменяя эти три значения. Однако мы всегда смотрим и вращаем m_target. m_target является локальным источником сферы. Однако мы можем свободно перемещать это происхождение в любое место в мировом пространстве.
Есть три основные функции камеры:
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
В простейших формах Rotate () и Zoom () тривиальны. Просто измените m_theta, m_phi и m_radius соответственно:
void Camera::Rotate(float dTheta, float dPhi) {
m_theta += dTheta;
m_phi += dPhi;
}
void Camera::Zoom(float distance) {
m_radius -= distance;
}
Панорамирование немного сложнее. Панорамирование камеры определяется как перемещение камеры влево / вправо и / или вверх / вниз относительно текущего вида камеры. Самый простой способ сделать это - преобразовать текущий вид камеры из сферических координат в декартовы. Это даст нам вверх и правильные векторы.
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);
}
Итак, во-первых, мы конвертируем нашу сферическую систему координат в декартову, чтобы получить вектор взгляда . Далее, мы делаем векторное произведение с вектором вверх , чтобы получить правильный вектор. Это вектор, который указывает прямо справа от вида камеры. Наконец, мы делаем еще одно векторное перекрестное произведение, чтобы поднять вектор камеры .
Чтобы закончить кастрюлю, мы перемещаем m_target вдоль вверх и правых векторов.
Один вопрос, который вы можете задать: зачем все время конвертировать между декартовым и сферическим (вам также придется конвертировать, чтобы создать матрицу представления).
Хороший вопрос. У меня тоже был этот вопрос и я пытался использовать исключительно декартово. У вас возникают проблемы с вращением. Поскольку операции с плавающей запятой не совсем точны, многократные вращения приводят к накоплению ошибок, которые медленно соответствуют камере и непреднамеренно вращаются.
Итак, в итоге я застрял со сферическими координатами. Чтобы противостоять дополнительным вычислениям, я закончил кэшировать матрицу вида и вычислять ее только при движении камеры.
Последний шаг - использовать этот класс Camera. Просто вызовите соответствующую функцию-член внутри функций MouseDown / Up / Scroll вашего приложения:
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);
}
Переменные m_camera * Factor - это просто масштабные коэффициенты, которые изменяют скорость вращения / панорамирования / прокрутки камеры.
Приведенный выше код представляет собой упрощенную версию системы камер с псевдокодом, которую я сделал для стороннего проекта: camera.h и camera.cpp . Камера пытается имитировать систему камер Майя. Код бесплатный и с открытым исходным кодом, поэтому не стесняйтесь использовать его в своем собственном проекте.