Qt OpenGL 实现交互功能(如鼠标、键盘操作)
一、基本概念
1. Qt 事件系统与 OpenGL 渲染的协同
Qt 提供了完善的事件处理机制,而 OpenGL 负责图形渲染。交互的实现本质上是:
-
事件捕获:通过 Qt 的事件系统(如
mousePressEvent
、keyPressEvent
)捕获用户输入。 -
状态更新:根据输入事件更新场景状态(如相机位置、模型变换矩阵等)。
-
重绘触发:调用
update()
请求重绘,触发paintGL()
重新渲染更新后的场景。
2. 坐标系转换
鼠标交互中的坐标系问题
-
屏幕坐标系(2D):鼠标事件的坐标
(x, y)
是屏幕像素坐标,原点在窗口左上角。 -
OpenGL 坐标系(3D):归一化设备坐标(NDC),范围为
[-1, 1]
,原点在中心。
转换方法:
-
鼠标坐标需通过视口变换和投影/视图矩阵的逆矩阵转换到 3D 世界坐标(例如实现鼠标拾取)。
-
示例代码片段:
cpp
// 将鼠标坐标转换为 NDC float x_ndc = (2.0f * mouseX) / width() - 1.0f; float y_ndc = 1.0f - (2.0f * mouseY) / height();
3. 相机控制原理
第一人称/第三人称相机
-
键盘控制移动:通过修改相机位置
cameraPos
,结合前向向量cameraFront
和上向量cameraUp
。cpp
// 前进:沿前向向量移动 cameraPos += cameraSpeed * cameraFront;
-
鼠标控制视角:通过鼠标移动计算偏航角(
yaw
)和俯仰角(pitch
),更新cameraFront
。cpp
QVector3D front; front.setX(cos(yaw) * cos(pitch)); front.setY(sin(pitch)); front.setZ(sin(yaw) * cos(pitch)); cameraFront = front.normalized();
投影矩阵的作用
-
透视投影(
perspective
):模拟人眼视角,通过fov
(视野)控制缩放效果。cpp
projection.perspective(fov, aspectRatio, nearPlane, farPlane);
4. 矩阵变换链
OpenGL 的渲染流程依赖以下矩阵变换:
-
模型矩阵(Model):定义物体自身的变换(平移、旋转、缩放)。
-
视图矩阵(View):定义相机的位置和朝向(通过
lookAt
计算)。 -
投影矩阵(Projection):定义如何将 3D 场景投影到 2D 屏幕。