camera.h

鼠标改变摄像机状态,从而调整lookAt视图矩阵

#pragma once
#include <qvector3d.h>
#include <QEvent>
#include <QMouseEvent>
#include <qmatrix4x4.h>
#include <qmath.h>
#include <qdebug.h>

const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 5.0f;
const float SENSITIVITY = 0.5f;
const float ZOOM = 45.0f;

class Camera
{
public:
Camera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH)
: Front(QVector3D(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;

updateCameraVectors();

FitView(1);
}

~Camera()
{
}

void Init(int width, int height)
{
SCR_WIDTH = width;
SCR_HEIGHT = height;
lastX = SCR_WIDTH / 2.0f;
lastY = SCR_HEIGHT / 2.0f;
firstMouse = true;
}

//根据新的俯仰角和偏航角求出相机的三个新的基向量
void updateCameraVectors()
{
QVector3D front;
front.setX(cos(qDegreesToRadians(Yaw)) * cos(qDegreesToRadians(Pitch)));
front.setY(sin(qDegreesToRadians(Pitch)));
front.setZ(sin(qDegreesToRadians(Yaw)) * cos(qDegreesToRadians(Pitch)));

Front = front.normalized();
Right = QVector3D::crossProduct(Front, WorldUp).normalized();
Up = QVector3D::crossProduct(Front, Right).normalized();
}

void FitView(int view)
{

}

QMatrix4x4 getViewMatrix()
{
QMatrix4x4 result;
result.lookAt(Position, Position + Front, Up);
return result;
}

bool handle(QEvent* event)
{
switch (event->type())
{
case QEvent::MouseMove://视角 旋转&平移
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
ProcessMousePress(mouseEvent);
}
break;
case QEvent::Wheel://视角缩放
{
auto wheelEvent = static_cast<QWheelEvent*>(event);
float moveDistance = 0.8f;
if (wheelEvent->angleDelta().y() > 0)
{
Position += Front * moveDistance;
}
else if (wheelEvent->angleDelta().y() < 0)
{
Position -= Front * moveDistance;
}
}
break;
case QEvent::MouseButtonRelease:
{
firstMouse = true;
}
break;
default:
return false;
}

return true;
}

void ProcessMousePress(QMouseEvent* event)
{
if (event->buttons() & Qt::LeftButton)
{
ProcessMouseLeftButtonPress(event);//鼠标左键移动,旋转视角
}
else if (event->buttons() & Qt::RightButton)
{
ProcessMouseRightButtonPress(event);//鼠标右键移动,平移视角
}
}

void ProcessMouseLeftButtonPress(QMouseEvent* event)//左键旋转
{
QPoint screenp = event->pos();
float xpos = screenp.x();
float ypos = screenp.y();

if (firstMouse)
{
lastX = xpos;
lastY = ypos;

firstMouse = false;
}

float xoffset = xpos - lastX;
float yoffset = lastY - ypos;

QVector3D center(0.0f, 0.0f, 0.0f);

lastX = xpos;
lastY = ypos;

ProcessMouseMovement(xoffset, yoffset, center);
}

void ProcessMouseMovement(float xoffset, float yoffset, QVector3D center, bool constrainPitch = true)//constrainPitch约束俯仰角
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;

Yaw += xoffset;
Pitch += yoffset;

if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}

QVector3D rPt(Position.x() - center.x(), Position.y() - center.y(), Position.z() - center.z());

float lx = QVector3D::dotProduct(rPt, Right);
float ly = QVector3D::dotProduct(rPt, Front);
float lz = QVector3D::dotProduct(rPt, Up);

updateCameraVectors();

Position = lx * Right + ly * Front + lz * Up;
Position.setX(Position.x() + center.x());
Position.setY(Position.y() + center.y());
Position.setZ(Position.z() + center.z());
}

void ProcessMouseRightButtonPress(QMouseEvent* event)//右键平移
{
float xpos = event->position().x();
float ypos = event->position().y();

QVector3D curPos(xpos / SCR_WIDTH, ypos / SCR_HEIGHT, 0.0f);
if (firstMouse)
{
movementPt = curPos;
startPosition = Position;
firstMouse = false;
}

auto off = MovementSpeed * (curPos - movementPt);
Position = startPosition + off.x() * Right + off.y() * Up;

lastX = xpos;
lastY = ypos;
}

public:
float Zoom = 45.0f;

private:
// camera Attributes
QVector3D Position;
QVector3D startPosition;
QVector3D movementPt;
QVector3D Front;
QVector3D Up;
QVector3D Right;
QVector3D WorldUp;
// euler Angles
float Yaw;//偏航角
float Pitch;//俯仰角
// camera options
float MovementSpeed;
float MouseSensitivity;

int SCR_WIDTH;
int SCR_HEIGHT;
float lastX;
float lastY;
bool firstMouse;

};

glview.cpp

#include <qopenglwidget.h>
#include <qopenglfunctions_4_5_core.h>
#include <qopenglshaderprogram.h>
#include <qopenglvertexarrayobject.h>
#include <qopenglbuffer.h>
#include <QMouseEvent>
#include "camera.h"

class GLWidget : public QOpenGLWidget ,protected QOpenGLFunctions_4_5_Core
{
Q_OBJECT

public:
GLWidget(QWidget* parent = nullptr)
{
setMouseTracking(true);
}
~GLWidget() {}

void initializeGL() override
{
initializeOpenGLFunctions();

initShader(m_shader, QString("./shader/LoadingShader.vert"), QString("./shader/LoadingShader.frag"));
initTriangle();
}

void resizeGL(int width,int height) override
{
glViewport(0, 0, width, height);
m_camera.Init(width, height);

m_projectionMat.setToIdentity();
m_projectionMat.perspective(45.0f, width / height, 0.1f, 100.0f);
}

void paintGL() override
{
glEnable(GL_DEPTH_TEST);

m_shader.bind();

m_modelMat.setToIdentity();

m_viewMat = m_camera.getViewMatrix();

//m_viewMat.lookAt(QVector3D(0.0f, 0.0f, 5.0f), QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 1.0f, 0.0f));
m_shader.setUniformValue("model", m_modelMat);
m_shader.setUniformValue("view", m_viewMat);
m_shader.setUniformValue("projection", m_projectionMat);
drawTriangle();
m_shader.release();
}

void initShader(QOpenGLShaderProgram& shader,const QString& vertShaderPath,const QString& fragShaderPath)
{
if (!shader.addShaderFromSourceFile(QOpenGLShader::Vertex, vertShaderPath) ||
!shader.addShaderFromSourceFile(QOpenGLShader::Fragment, fragShaderPath) ||
!shader.link())
{
qDebug() << shader.log();
}
}

void initTriangle()
{
float vertices[] =
{
//position color
-0.5f,0.0f,0.5f, 0.5f,0.5f,0.0f,
0.0f,0.5f,0.5f, 0.5f,0.5f,0.5f,
0.5f,0.0f,0.5f, 0.5f,0.0f,0.5f,
};

glGenVertexArrays(1, &m_vao);
glGenBuffers(1, &m_vbo);

glBindVertexArray(m_vao);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);

glBindVertexArray(0);
}

void drawTriangle()
{
glBindVertexArray(m_vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
}

protected:
bool event(QEvent* e) override
{
m_camera.handle(e);
update();

return QWidget::event(e);
}

private:
QOpenGLShaderProgram m_shader;
unsigned int m_vao, m_vbo;

QMatrix4x4 m_modelMat;
QMatrix4x4 m_viewMat;
QMatrix4x4 m_projectionMat;
Camera m_camera = Camera(QVector3D(0.0f, 0.0f, 5.0f));
};

[源码下载]