https://learnopengl-cn.github.io/01%20Getting%20started/09%20Camera/#_8
https://www.jianshu.com/p/003b1fb8d6d3
#include "ACamera.h" #include <QDebug> ACamera::ACamera(QVector3D position, QVector3D up, float yaw, float pitch) : position(position), worldUp(up), front(-position), picth(pitch), yaw(yaw), movementSpeed(SPEED), mouseSensitivity(SENSITIVITY), zoom(ZOOM) { this->updateCameraVectors(); for(uint i = 0; i != 1024; ++i) keys[i] = false; } ACamera::~ACamera() { } // Returns the view matrix calculated using Euler Angles and the LookAt Matrix QMatrix4x4 ACamera::getViewMatrix() { QMatrix4x4 view; view.lookAt(this->position, this->position + this->front, this->up); return view; } // Processes input received from any keyboard-like input system. Accepts input parameter in the form of ACamera defined ENUM (to abstract it from windowing systems) void ACamera::processKeyboard(Camera_Movement direction, float deltaTime) { float velocity = this->movementSpeed * deltaTime; if (direction == FORWARD) this->position += this->front * velocity; if (direction == BACKWARD) this->position -= this->front * velocity; if (direction == LEFT) this->position += this->right * velocity; if (direction == RIGHT) this->position -= this->right * velocity; if (direction == UP) this->position += this->worldUp * velocity; if (direction == DOWN) this->position -= this->worldUp * velocity; } // Processes input received from a mouse input system. Expects the offset value in both the x and y direction. void ACamera::processMouseMovement(float xoffset, float yoffset, bool constraintPitch) { xoffset *= this->mouseSensitivity; yoffset *= this->mouseSensitivity; this->yaw += xoffset; this->picth += yoffset; if (constraintPitch) { if (this->picth > 89.0f) this->picth = 89.0f; if (this->picth < -89.0f) this->picth = -89.0f; } this->updateCameraVectors(); } // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis void ACamera::processMouseScroll(float yoffset) { if (this->zoom >= 1.0f && this->zoom <= 45.0f) this->zoom -= yoffset; if (this->zoom > 45.0f) this->zoom = 45.0f; if (this->zoom < 1.0f) this->zoom = 1.0f; } void ACamera::processInput(float dt) { if (keys[Qt::Key_W]) processKeyboard(FORWARD, dt); if (keys[Qt::Key_S]) processKeyboard(BACKWARD, dt); if (keys[Qt::Key_A]) processKeyboard(LEFT, dt); if (keys[Qt::Key_D]) processKeyboard(RIGHT, dt); if (keys[Qt::Key_E]) processKeyboard(UP, dt); if (keys[Qt::Key_Q]) processKeyboard(DOWN, dt); } void ACamera::updateCameraVectors() { // Calculate the new Front vector QVector3D front; front.setX(cos(this->yaw) * cos(this->picth)); front.setY(sin(this->picth)); front.setZ(sin(this->yaw) * cos(this->picth)); this->front = front.normalized(); this->right = QVector3D::crossProduct(this->front, this->worldUp).normalized(); this->up = QVector3D::crossProduct(this->right, this->front).normalized(); }
#ifndef ACAMERA_H #define ACAMERA_H #include <QVector3D> #include <QMatrix4x4> #include <QKeyEvent> // Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods enum Camera_Movement { FORWARD, BACKWARD, LEFT, RIGHT, UP, DOWN }; // Default camera values const float YAW = -90.0f; const float PITCH = 0.0f; const float SPEED = 1.0f; const float SENSITIVITY = 0.0001f; const float ZOOM = 45.0f; class ACamera { public: ACamera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH); ~ACamera(); QMatrix4x4 getViewMatrix(); void processMouseMovement(float xoffset, float yoffset, bool constraintPitch = true); void processMouseScroll(float yoffset); void processInput(float dt); QVector3D position;// 摄像机位置 QVector3D worldUp; // 上向量 QVector3D front;// 摄像机方向向量 / QVector3D up; // 上轴 QVector3D right; // 右轴 //Eular Angles float picth; // 俯仰角 float yaw; // 偏航角 //Camera options float movementSpeed; float mouseSensitivity; float zoom; //Keyboard multi-touch bool keys[1024]; private: void updateCameraVectors(); void processKeyboard(Camera_Movement direction, float deltaTime); }; #endif // ACAMERA_H
#include "aqtfunwidget.h" #include <QDebug> #include <QTimer> AQtFunWidget::AQtFunWidget(QWidget *parent) : QOpenGLWidget(parent), vbo(QOpenGLBuffer::VertexBuffer) { m_camera = new ACamera(QVector3D(5.0f,0.0f,10.0f)); m_bLeftPressed = false; m_pTimer = new QTimer(this); connect(m_pTimer,&QTimer::timeout,this,[=]{ m_nTimeValue += 1; update(); }); m_pTimer->start(40); } AQtFunWidget::~AQtFunWidget() { makeCurrent(); vbo.destroy(); vao.destroy(); delete texture1; delete texture2; doneCurrent(); } void AQtFunWidget::initializeGL() { this->initializeOpenGLFunctions(); bool success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/textures.vert"); if (!success){ qDebug() << "load vert file failded." << shaderProgram.log(); return; } success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/textures.frag"); if (!success){ qDebug() << "load fag file failded." << shaderProgram.log(); return; } success = shaderProgram.link(); if (!success){ qDebug() << "shaderProgram link failded." << shaderProgram.log(); } //VAO,VBO data float vertices[] = { -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 }; QOpenGLVertexArrayObject::Binder vaobinD(&vao); vbo.create(); vbo.bind(); vbo.allocate(vertices,sizeof(vertices)); // position attribute int attr = -1; attr = shaderProgram.attributeLocation("aPos"); shaderProgram.setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 5); shaderProgram.enableAttributeArray(attr); // texture coord attribute attr = shaderProgram.attributeLocation("aTexCoord"); shaderProgram.setAttributeBuffer(attr, GL_FLOAT, sizeof(GLfloat) * 3, 2, sizeof(GLfloat) * 5); shaderProgram.enableAttributeArray(attr); // texture 1 // --------- texture1 = new QOpenGLTexture(QImage(":/image/container.jpg"), QOpenGLTexture::GenerateMipMaps); if(!texture1->isCreated()){ qDebug() << "Failed to load texture"; } // set the texture wrapping parameters texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat); texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat); // set texture filtering parameters texture1->setMinificationFilter(QOpenGLTexture::Linear); texture1->setMagnificationFilter(QOpenGLTexture::Linear); // texture 2 // --------- texture2 = new QOpenGLTexture(QImage(":/image/awesomeface.png").mirrored(true, true), QOpenGLTexture::GenerateMipMaps); if(!texture2->isCreated()){ qDebug() << "Failed to load texture"; } // set the texture wrapping parameters texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat); texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat); // set texture filtering parameters texture2->setMinificationFilter(QOpenGLTexture::Linear); texture2->setMagnificationFilter(QOpenGLTexture::Linear); // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) shaderProgram.bind(); // don't forget to activate/use the shader before setting uniforms! shaderProgram.setUniformValue("texture1", 0); shaderProgram.setUniformValue("texture2", 1); vbo.release(); // configure global opengl state // ----------------------------- glEnable(GL_DEPTH_TEST); } void AQtFunWidget::resizeGL(int w, int h) { glViewport(0,0,w,h); } static 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) }; void AQtFunWidget::paintGL() { glClearColor(0.2f,0.3f,0.3f,1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); m_camera->processInput(1.0f); glActiveTexture(GL_TEXTURE0); texture1->bind(); glActiveTexture(GL_TEXTURE1); texture2->bind(); shaderProgram.bind(); QMatrix4x4 projection; projection.perspective(m_camera->zoom,1.0f*width()/height(),0.1f,100.0f); shaderProgram.setUniformValue("projection",projection); shaderProgram.setUniformValue("view",m_camera->getViewMatrix()); // render box 渲染箱子 { QOpenGLVertexArrayObject::Binder vaobind(&vao); for (int i = 0; i < 10; i++) { QMatrix4x4 model; model.translate(cubePositions[i]); float angle = m_nTimeValue*(1.0f+i); model.rotate(angle,QVector3D(1.0f,0.3f,0.5f)); shaderProgram.setUniformValue("model",model); glDrawArrays(GL_TRIANGLES,0,36); } } texture1->release(); texture2->release(); shaderProgram.release(); } void AQtFunWidget::keyPressEvent(QKeyEvent *event) { int key = event->key(); if (key >0 && key < 1024){ m_camera->keys[key] = true; } } void AQtFunWidget::keyReleaseEvent(QKeyEvent *event) { int key = event->key(); if (key >0 && key < 1024){ m_camera->keys[key] = false; } } void AQtFunWidget::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton){ m_bLeftPressed = true; m_lastPos = event->pos(); } } void AQtFunWidget::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); m_bLeftPressed = false; } void AQtFunWidget::mouseMoveEvent(QMouseEvent *event) { if(m_bLeftPressed){ int xPos = event->pos().x(); int yPos = event->pos().y(); int xOffset = m_lastPos.x() - xPos; int yOffset = yPos - m_lastPos.y(); m_camera->processMouseMovement(xOffset,yOffset); } } void AQtFunWidget::wheelEvent(QWheelEvent *event) { QPoint offset = event->angleDelta(); m_camera->processMouseScroll(offset.y()/20.0f); }
#ifndef AQTFUNWIDGET_H #define AQTFUNWIDGET_H #include <QWidget> #include <QOpenGLWidget> #include <QOpenGLShaderProgram> #include <QOpenGLFunctions> #include <QOpenGLVertexArrayObject> #include <QOpenGLBuffer> #include <QOpenGLTexture> #include "ACamera.h" class AQtFunWidget : public QOpenGLWidget,protected QOpenGLFunctions { Q_OBJECT public: AQtFunWidget(QWidget *parent = 0); ~AQtFunWidget(); protected: virtual void initializeGL() Q_DECL_OVERRIDE; virtual void resizeGL(int w, int h) Q_DECL_OVERRIDE; virtual void paintGL() Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; private: QOpenGLShaderProgram shaderProgram; QOpenGLBuffer vbo; QOpenGLVertexArrayObject vao; QOpenGLTexture *texture1 = nullptr; QOpenGLTexture *texture2 = nullptr; QTimer* m_pTimer = nullptr; int m_nTimeValue = 0; // camera ACamera *m_camera; bool m_bLeftPressed; QPoint m_lastPos; }; #endif // AQTFUNWIDGET_H