前言
本篇是在上一篇【qt openGL入门笔记】FPS相机-CSDN博客的基础上增加轨道相交功能。两种相机在概念上是不一样的,FPS相机是以第一人称行走时"眼睛"的角度看物体的变化;而轨道相交是绕着目标点转,类似于绕着轨道转动的卫星(视角是一直看着目标点)。
效果图

功能详解
整体改动较小,主要改动在渲染和键值响应上。
键值改动
GLWidget类中,增加了多Key_Space键值捕获,用于切换相机模式。
鼠标点击事件传递进Camera类中,增加了右键和中键的平移,左键的绕目标旋转效果
if (m_mode == Mode::Orbit) {
if (m_rotating) { // 左键:绕目标旋转
m_yaw += dx * m_lookSensitivity;
m_pitch = qBound(-89, m_pitch + dyUp * ..., 89);
} else if (m_panning) { // 右键:平移目标点(平移视角)
const float wpp = worldPerPixel();
m_target -= m_right * (dx * wpp);
m_target -= m_up * (dyUp * wpp);
}
} else {
if (m_rotating) { /* FPS:只有左键转视角 */ }
}
//屏幕上拖动 1 个像素,等于世界里平移了多少单位
float Camera::worldPerPixel() const
{
const float h = m_viewportH > 0 ? float(m_viewportH) : 800.0f;
return 2.0f * m_orbitDistance * qTan(qDegreesToRadians(m_fov) * 0.5f) / h;
}
新增了滚轮的缩放效果
if (m_mode == Mode::Orbit) {//滚轮缩放
m_orbitDistance *= qPow(0.85f, steps);
m_orbitDistance = qBound(m_minDistance, m_orbitDistance, m_maxDistance);
} else {
m_moveSpeed *= qPow(1.15f, steps);
m_moveSpeed = qBound(1.0f, m_moveSpeed, 300.0f);
}
重置功能的变化
// ============================================================
// F 复位:只复位"当前模式",不切换模式
// ============================================================
void Camera::reset()
{
m_keysHeld.clear();
m_rotating = m_panning = false;
if (m_mode == Mode::FPS) {
applySpawnPose(m_mode); // FPS:瞬间重置
updateCameraVectors();
return;
}
// Orbit:记录起点,0.6s 缓动飞回默认机位
const QVector3D& eye = m_spawnEye[int(m_mode)];
const QVector3D& center = m_spawnCenter[int(m_mode)];
const QVector3D dir = (center - eye).normalized();
m_flyToYaw = qRadiansToDegrees(qAtan2(dir.z(), dir.x()));
m_flyToPitch = qRadiansToDegrees(qAsin(qBound(-1.0f, dir.y(), 1.0f)));
m_flyToDist = (center - eye).length();
m_flyToTarget = center;
m_flyFromYaw = m_yaw;
m_flyFromPitch = m_pitch;
m_flyFromDist = m_orbitDistance;
m_flyFromTarget = m_target;
m_flyT = 0.0f;
m_flying = true;
}
渲染改动
updateCameraVectors()增加重新计算了m_position,不是FPS相机的"跟随移动",而是"绕着目标转"
if (m_mode == Mode::Orbit) {
m_position = m_target - m_front * m_orbitDistance;
}
新增了模式切换函数
// ============================================================
// 模式切换(保持视角连续)
// ============================================================
void Camera::setMode(Mode mode)
{
if (mode == m_mode) return;
m_flying = false; // 切模式打断飞行动画
if (mode == Mode::Orbit) {
m_target = m_position + m_front * m_orbitDistance;
}
m_mode = mode;
m_rotating = false;
m_panning = false;
m_keysHeld.clear();
updateCameraVectors();
}
需要注意的时,视图矩阵函数viewMatrix()和投影矩阵函数projectionMatrix()中的公式是没有变化的,但是公式里面的成员变量m_position, m_position + m_front, m_worldUp已经在键值变化时,一起变化了,所以VP也是一起变化的。