摄像机类
根据上一篇的的内容,实现一个摄像机类,头文件如下:
#ifndef CAMERA_H
#define CAMERA_H
#include <QMatrix4x4>
#include <QVector3D>
class Camera
{
public:
enum Movement
{
FORWARD = 0,
BACKWARD,
LEFT,
RIGHT
};
Camera(float yaw = 90.0f, float pitch = 0.0f, const QVector3D& position = QVector3D(0.0f, 0.0f, 0.0f),
const QVector3D& up = QVector3D(0.0f, 1.0f, 0.0f),
const QVector3D& front = QVector3D(0.0f, 0.0f, 1.0f));
~Camera();
QMatrix4x4 getViewMatrix();
void processKeyboard(Movement direction, float deltaTime);
void processMouseMovement(float xoffset, float yoffset, bool constrainPitch = true);
void processMouseScroll(float yoffset);
void updateCameraVectors();
float getZoom() const { return m_zoom; }
private:
QVector3D m_position;
QVector3D m_up;
QVector3D m_front;
QVector3D m_right;
QVector3D m_worldUp;
float m_yaw;
float m_pitch;
float m_moveSpeed;
float m_mouseSensitivity;
float m_zoom;
};
#endif
Movement
枚举表示摄像机移动的四个方向。Camera
构造函数中给出位置向量、上/前/右向量的初始值,以及 yaw、pitch 的初始角度。getViewMatrix
返回摄像机的某一时刻的视图矩阵。processKeyboard
处理摄像机收到的键盘事件,更新位置向量。processMouseMovement
处理摄像机收到的鼠标移动事件,更新偏转角度。processMouseScroll
处理摄像机收到的鼠标滚轮事件,更新缩放比。updateCameraVectors
根据偏转角度对向量进行更新,用于计算视图矩阵。
通过 Camera 类,可以帮助处理前后左右的位置移动,鼠标进行的视角移动和滚轮的缩放变换,通过更新 Camera 的实时状态就能在 3D 空间自由移动~
自由移动
在 3D 空间移动的核心就是实时修改视图矩阵,这里的 3D 场景仍然沿用之前坐标系统讲解中的 3D 箱子场景,具体场景的绘制流程就不再赘述了。需要关注的是在绘制函数中,视图矩阵和透视矩阵会根据摄像机类的返回值进行确定,就像下面这样:
QMatrix4x4 view;
QMatrix4x4 projection;
projection.perspective(m_camera->getZoom(), (float)width() / (float)height(), 0.1f, 100.0f);
view = m_camera->getViewMatrix();
m_shaderProgram->setMat4("view", view);
m_shaderProgram->setMat4("projection", projection);
为了实现在 3D 场景中移动,需要将鼠标键盘事件传递给 Camera 类,实现如下:
void OpenGLCamera_01::keyPressEvent(QKeyEvent *event)
{
float deltaTime = 0.1f; // 这里先给个固定值
if (event->key() == Qt::Key_W)
m_camera->processKeyboard(Camera::FORWARD, deltaTime);
if (event->key() == Qt::Key_S)
m_camera->processKeyboard(Camera::BACKWARD, deltaTime);
if (event->key() == Qt::Key_A)
m_camera->processKeyboard(Camera::LEFT, deltaTime);
if (event->key() == Qt::Key_D)
m_camera->processKeyboard(Camera::RIGHT, deltaTime);
update();
}
void OpenGLCamera_01::mouseMoveEvent(QMouseEvent *event)
{
if (m_bfirstMouse)
{
m_lastMouseX = event->x();
m_lastMouseY = event->y();
m_bfirstMouse = false;
}
float xoffset = event->x() - m_lastMouseX;
float yoffset = m_lastMouseY - event->y();
m_lastMouseX = event->x();
m_lastMouseY = event->y();
m_camera->processMouseMovement(xoffset, yoffset);
update();
}
void OpenGLCamera_01::wheelEvent(QWheelEvent *event)
{
float yoffset = event->angleDelta().y() * 0.05;
m_camera->processMouseScroll(yoffset);
update();
}
通过实现 QWidget
的 keyPressEvent
、mouseMoveEvent
和 wheelEvent
,分别将键盘按下、鼠标移动和滚轮滚动事件传递给 Camera
类,Camera
根据预先处理逻辑对视图矩阵进行变换,实现在 3D 场景中的移动。这里的 update
是 Qt 中用于绘制刷新的函数,当视图矩阵发生改变时,我们期望视图进行更新。另外需要注意的是,需要给 OpenGLCamera_01
控件设置 mouseTracking
属性,默认情况下 Qt 控件只会捕捉鼠标按下后的移动事件,如果需要直接捕获鼠标移动事件则需要设置 mouseTracking
。
实现效果
如果一切顺利,会得到下面的效果:
关注公众号:C++学习与探索,有惊喜哦~