摄像机类是基于坐标系统实现的,有关坐标系统:坐标系统。
摄像机基类
.h
#ifndef QTOPENGL_CAMERA_H
#define QTOPENGL_CAMERA_H#include<QMatrix4x4>
#include <vector>
#include <QOpenGLShaderProgram>#define PI 3.141592653589793638
// 移动方向枚举量. 是一种抽象,以避开特定于窗口系统的输入方法
// 我们这里是WSAD
enum Camera_Movement {emFORWARD,emBACKWARD,emLEFT,emRIGHT,emUP,emDOWN
};// 默认值
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.5f;
const float ZOOM = 45.0f;// 一个抽象的camera类,用于处理输入并计算相应的Euler角度、向量和矩阵,以便在OpenGL中使用
class Camera
{
public:// constructor with vectorsexplicit Camera(QVector3D position = QVector3D(0.0f, 0.0f, 3.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH);// constructor with scalar valuesCamera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch);// returns the view matrix calculated using Euler Angles and the LookAt MatrixQMatrix4x4 getViewMatrix();// 处理从任何类似键盘的输入系统接收的输入。接受摄像机定义枚举形式的输入参数(从窗口系统中提取)void processKeyboard(Camera_Movement direction, float deltaTime);// 处理从鼠标输入系统接收的输入。需要x和y方向上的偏移值。void processMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true);// 处理从鼠标滚轮事件接收的输入。仅需要在垂直车轮轴上输入void processMouseScroll(float yoffset);void setPosition(const QVector3D &position);QVector3D getPosition();void setFront(const QVector3D &front);QVector3D getFront();void setUp(const QVector3D &up);QVector3D getUp();void setRight(const QVector3D &right);QVector3D getRight();void setWorldUp(const QVector3D &worldUp);QVector3D getWorldUp();void setYaw(const float &yaw);float getYaw() const;void setPitch(const float &pitch);float getPitch() const;void setMovementSpeed(const float &movementSpeed);float getMovementSpeed() const;void setMouseSensitivity(const float &mouseSensitivity);float getMouseSensitivity() const;void setZoom(const float &zoom);float getZoom() const;
private:// 根据相机的(更新的)Euler角度计算前矢量void updateCameraVectors();
private:QVector3D m_position; // 摄像机位置QVector3D m_front; // 前后移动值QVector3D m_up; // 上下移动值QVector3D m_right; // 左右移动值QVector3D m_worldUp;float m_yaw; // euler Anglesfloat m_pitch;// camera optionsfloat m_movementSpeed;float m_mouseSensitivity;float m_zoom;};#endif //QTOPENGL_CAMERA_H
.cpp
#include "camera.h"Camera::Camera(QVector3D position, QVector3D up, float yaw, float pitch): m_front(QVector3D(0.0f, 0.0f, 0.0f)), m_movementSpeed(SPEED), m_mouseSensitivity(SENSITIVITY), m_zoom(ZOOM)
{m_position = position;m_worldUp = up;m_yaw = yaw;m_pitch = pitch;qDebug()<<m_worldUp; //QVector3D(0, 1, 0)//摄像机初始化时候调用此函数进行局部坐标的初始化updateCameraVectors();
}Camera::Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch): m_front(QVector3D(0.0f, 0.0f, 0.0f)), m_movementSpeed(SPEED), m_mouseSensitivity(SENSITIVITY), m_zoom(ZOOM)
{m_position = QVector3D(posX, posY, posZ);m_worldUp = QVector3D(upX, upY, upZ);m_yaw = yaw;m_pitch = pitch;updateCameraVectors();
}QMatrix4x4 Camera::getViewMatrix()
{QMatrix4x4 theMatrix;//m_position + m_front是指向这个方向向量,,而单独的m_front是指向那个点theMatrix.lookAt(m_position, m_position + m_front, m_up); //保证摄像机始终注视前方return theMatrix;
}void Camera::processKeyboard(Camera_Movement direction, float deltaTime)
{float velocity = m_movementSpeed * deltaTime;if (direction == emFORWARD)m_position += m_front * velocity;if (direction == emBACKWARD)m_position -= m_front * velocity;if (direction == emLEFT)m_position -= m_right * velocity;if (direction == emRIGHT)m_position += m_right * velocity;if (direction == emUP)m_position -= m_up * velocity;if (direction == emDOWN)m_position += m_up * velocity;
}void Camera::processMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch)
{xoffset *= m_mouseSensitivity;yoffset *= m_mouseSensitivity;m_yaw += xoffset;m_pitch += yoffset;// 确保当投球超出边界时,屏幕不会翻转if (constrainPitch){if (m_pitch > 89.0f)m_pitch = 89.0f;if (m_pitch < -89.0f)m_pitch = -89.0f;}// 使用更新的Euler角度更新前、右和上矢量updateCameraVectors();
}void Camera::processMouseScroll(float yoffset)
{m_zoom -= (float)yoffset;if (m_zoom < 1.0f)m_zoom = 1.0f;if (m_zoom > 75.0f)m_zoom = 75.0f;
}#include<cmath>
void Camera::updateCameraVectors()
{// calculate the new Front vectorQVector3D front;front.setX(cos(m_yaw*PI/180.0) * cos(m_pitch*PI/180.0));front.setY( sin(m_pitch*PI/180.0));front.setZ(sin(m_yaw*PI/180.0) * cos(m_pitch*PI/180.0));front.normalize();m_front = front;// also re-calculate the Right and Up vectorm_right = QVector3D::crossProduct(m_front, m_worldUp);// 标准化向量,因为向上或向下看得越多,向量的长度就越接近0,这会导致移动速度变慢。m_right.normalize();m_up = QVector3D::crossProduct(m_right, m_front);m_up.normalize();
}QVector3D Camera::getPosition()
{return m_position;
}void Camera::setPosition(const QVector3D &position)
{m_position = position;
}void Camera::setFront(const QVector3D &front)
{m_front = front;
}QVector3D Camera::getFront()
{return m_front;
}void Camera::setUp(const QVector3D &up)
{m_up = up;
}QVector3D Camera::getUp()
{return m_up;
}void Camera::setRight(const QVector3D &right)
{m_right = right;
}QVector3D Camera::getRight()
{return m_right;
}void Camera::setWorldUp(const QVector3D &worldUp)
{m_worldUp = worldUp;
}QVector3D Camera::getWorldUp()
{return m_worldUp;
}void Camera::setYaw(const float &yaw)
{m_yaw = yaw;
}float Camera::getYaw() const
{return m_yaw;
}void Camera::setPitch(const float &pitch)
{m_pitch = pitch;
}float Camera::getPitch() const
{return m_pitch;
}void Camera::setMovementSpeed(const float &movementSpeed)
{m_movementSpeed = movementSpeed;
}float Camera::getMovementSpeed() const
{return m_movementSpeed;
}void Camera::setMouseSensitivity(const float &mouseSensitivity)
{m_mouseSensitivity = mouseSensitivity;
}float Camera::getMouseSensitivity() const
{return m_mouseSensitivity;
}void Camera::setZoom(const float &zoom)
{m_zoom = zoom;
}float Camera::getZoom() const
{return m_zoom;
}
自定义opengl窗口代码
.h
#ifndef MYOPENGL_H
#define MYOPENGL_H#include<QOpenGLWidget>
#include<QOpenGLFunctions_3_3_Core>
#include<QOpenGLShaderProgram>
#include<QOpenGLTexture>
#include<camera.h>
class MyOpenGL : public QOpenGLWidget,public QOpenGLFunctions_3_3_Core
{
public:explicit MyOpenGL(QWidget *parent = nullptr);~MyOpenGL();enum Shape{None,Rect,Circle,Triangle,RectWireframe};// QOpenGLWidget interface
protected:void initializeGL(); //初始化glvoid resizeGL(int w, int h);void paintGL(); //重绘//void mouseMoveEvent(QMouseEvent *event);void keyPressEvent(QKeyEvent *event);void mouseMoveEvent(QMouseEvent *event);
private:GLuint VAO = 0;GLuint VBO = 0;GLuint EBO = 0;Shape shape;QOpenGLShaderProgram *myshaderprogram = nullptr;QOpenGLTexture *texture1 = nullptr;QVector3D cameraPos; //相机位置QVector3D cameraLookAtDerection; //相机正方向QVector3D cameraRightDirection; //相机右方向/** projection矩阵中的fov角度* fov(field of View) 定义了可以看到场景中多大的范围。当视野变小时,场景投影出来的空间就会减小,* 产生放大(Zoom In)的感觉*/float m_fov; //角度Camera camera;QVector3D camera_position_;// QWidget interface
protected:void mousePressEvent(QMouseEvent *event);
// void mouseReleaseEvent(QMouseEvent *event);
};#endif // MYOPENGL_H
.cpp
#include "myopengl.h"
#include <QKeyEvent>
#include<iostream>
#include<cmath>
MyOpenGL::MyOpenGL(QWidget *parent): QOpenGLWidget(parent)
{
//设置聚焦模式
setFocusPolicy(Qt::StrongFocus);}MyOpenGL::~MyOpenGL()
{if(!isValid()) return; // 如果控件和OpenGL资源(如上下文)已成功初始化,则返回true。this->makeCurrent(); // 通过将相应的上下文设置为当前上下文并在该上下文中绑定帧缓冲区对象,为呈现此小部件的OpenGL内容做准备。this->doneCurrent(); // 释放上下文// 释放glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glDeleteVertexArrays(1, &VAO);myshaderprogram->release();texture1->release();myshaderprogram->removeAllShaders();}float vertices[] = {// positions // colors-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};GLuint index[] = {0,1,3,1,2,3
};QVector<QVector3D> cubePositions = {QVector3D(0.0f, 0.0f, 0.0f),QVector3D(2.0f, 5.0f, -15.0f),QVector3D(-1.5f, -2.2f, -2.5f),QVector3D(-3.8f, -2.0f, -12.3f),QVector3D(2.4f, -0.4f, -3.5f),QVector3D(-1.7f, 3.0f, -7.5f),QVector3D(1.3f, -2.0f, -2.5f),QVector3D(1.5f, 2.0f, -2.5f),QVector3D(1.5f, 0.2f, -1.5f),QVector3D(-1.3f, 1.0f, -1.5f)
};
bool gamma = true;
bool gamma2 = false;
void MyOpenGL::initializeGL()
{initializeOpenGLFunctions(); //初始化方法GLint vertexAttributeCount;glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &vertexAttributeCount);qDebug() << "GL_MAX_VERTEX_ATTRIBS count = " << vertexAttributeCount;//加载shader脚本程序myshaderprogram = new QOpenGLShaderProgram(this);myshaderprogram->addShaderFromSourceFile(QOpenGLShader::Vertex,":/new/prefix1/vertex.vsh");myshaderprogram->addShaderFromSourceFile(QOpenGLShader::Fragment,":/new/prefix1/fragment.fsh");myshaderprogram->link();myshaderprogram->bind();//获取属性idGLuint posAttr = GLuint(myshaderprogram->attributeLocation("aPos"));GLuint texCord = GLuint(myshaderprogram->attributeLocation("aTexCord"));//vao,vbo,ebo初始化glGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);glGenBuffers(1,&EBO);//绑定vao和vbo对象,eboglBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);//为缓冲对象创建一个新的数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(index),index,GL_STATIC_DRAW);//设置顶点属性glVertexAttribPointer(posAttr,3,GL_FLOAT,GL_FALSE,5*sizeof(float),(void*)0);// 开启VAO管理的第一个属性值glEnableVertexAttribArray(posAttr);//设置纹理属性glVertexAttribPointer(texCord,2,GL_FLOAT,GL_FALSE,5*sizeof(float),(void*)(3 * sizeof(float)));// 开启VAO管理的第一个属性值glEnableVertexAttribArray(texCord);//声明纹理texture1 = new QOpenGLTexture(QOpenGLTexture::Target2D);// 设置纹理格式texture1->setFormat(QOpenGLTexture::RGBA8_UNorm); // 注意:R8_UNorm 通常用于单通道灰度图像// 加载图像并设置到纹理中QImage image1(":/new/prefix1/D:/12929/Desktop/1.jpeg"); // 确保路径正确if (!image1.isNull() ) {qDebug() << " load images.";// 自动根据图像大小分配纹理存储并设置数据texture1->create(); // 这将自动根据 image1 的大小设置纹理大小texture1->setData(image1.mirrored()); //传入镜像,对y翻转} else {qDebug() << "Failed to load images.";// 处理图像加载失败的情况}//设置纹理单元的分配索引0和1,在patinGL中进行Bindmyshaderprogram->setUniformValue("texture1",0);}void MyOpenGL::resizeGL(int w, int h)
{}void MyOpenGL::paintGL()
{// 设置Clear的属性glClearColor(0.0f,0.0f,0.0f,0.0f);//启动深度测试glEnable(GL_DEPTH_TEST);// 使用glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);myshaderprogram->bind();texture1->bind(0);glBindVertexArray(VAO);//映射矩阵QMatrix4x4 projection;//设置映射属性值projection.perspective(75, float(width()) / float(height()), 0.1f, 100.0f);myshaderprogram->setUniformValue("projection", projection);//观察矩阵QMatrix4x4 view = camera.getViewMatrix();
// QMatrix4x4 view ;
// view.translate(0.0f, 0.0f, -3.0f);myshaderprogram->setUniformValue("view", view);//模型矩阵QMatrix4x4 model;for (unsigned int i = 0; i < 10; ++i){//将模型的变换矩阵重置为单位矩阵model.setToIdentity();//这行代码将模型沿着某个向量(cubePositions[i])进行平移变换。cubePositions[i]是一个包含三个元素的数组或向量,分别代表在X、Y、Z轴上的平移量。这意味着模型将被移动到新的位置,该位置由cubePositions[i]定义。model.translate(cubePositions[i]);float angle = 20.0f * i;model.rotate(angle, 1.0f, 0.3f, 0.5f);myshaderprogram->setUniformValue("model", model);glDrawArrays(GL_TRIANGLES, 0, 36);}//update();
}void MyOpenGL::keyPressEvent(QKeyEvent *event)
{qDebug()<<"keyPressEvent";switch (event->key()){case Qt::Key_W:camera.processKeyboard(Camera_Movement::emFORWARD, 0.05);break;case Qt::Key_A:camera.processKeyboard(Camera_Movement::emLEFT, 0.05);break;case Qt::Key_S:camera.processKeyboard(Camera_Movement::emBACKWARD, 0.05);break;case Qt::Key_D:camera.processKeyboard(Camera_Movement::emRIGHT, 0.05);break;case Qt::Key_Q:camera.processKeyboard(Camera_Movement::emUP, 0.05);break;case Qt::Key_E:camera.processKeyboard(Camera_Movement::emDOWN, 0.05);break;case Qt::Key_Space:camera.setPosition(camera_position_);break;case Qt::Key_T:gamma = !gamma;break;}update();
}QPoint lastPos;
void MyOpenGL::mouseMoveEvent(QMouseEvent *event)
{makeCurrent(); //确保opengl窗口为当前上下文qDebug()<<"mouseMoveEvent:";//获取位置auto currentPos = event->pos();QPoint deltaPos = currentPos -lastPos ;lastPos = currentPos;//更新位置camera.setYaw(camera.getYaw()+deltaPos.x());camera.setPitch(camera.getPitch()+deltaPos.y());if(event->buttons() & Qt::LeftButton){camera.processMouseMovement(deltaPos.x(),-deltaPos.y());}update();doneCurrent();}void MyOpenGL::mousePressEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){lastPos = event->pos();}
}