qt openGL入门笔记】FPS相机和轨道相机

前言

本篇是在上一篇【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也是一起变化的。

相关推荐
小鱼仙官7 小时前
使用Qt封装C/C++ 动态库 用于第三方调用
c语言·c++·qt
扶尔魔ocy9 小时前
【QT OpenGL】知识点编目及传送门
qt·opengl·osg
qq_4017004110 小时前
Qt Modbus 源码剖析:从 QModbusClient 到工业级通信框架
开发语言·qt·系统架构
GreenHandBruce10 小时前
基于Qt 6.12.0 + FFmpeg 9.0.2的4k视频播放器
qt·ffmpeg·音视频
誰能久伴不乏13 小时前
桌面客户端的运行日志系统:SQLite 分块 + 独立写线程 + 文本降级
数据库·c++·qt·架构·sqlite
沫璃染墨1 天前
《Qt从零入门系列(十五):Qt线程安全与锁机制详解——从QMutex到RAII与读写锁实战》
开发语言·c++·qt·安全·交互·线程·qt6.3
小豆庄1 天前
视频脱敏引擎的追踪难题:转场误判定、ID撞号和淡入窗口
qt·算法·目标检测·音视频·视频·敏捷流程
小灰灰搞电子1 天前
Qt 中使用 QSettings 存储结构体数据详解
开发语言·qt
LaoWaiHang2 天前
关于Qt中鼠标左键事件被子控件截留的处理
qt
初阳7852 天前
【基于Qt5仿音乐播放器(一)】——项目准备
qt·1024程序员节