摄像机

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();
}
ACamera.cpp
#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
ACamera.hpp
#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);
}
Widget.cpp
#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
.hpp
原文地址:https://www.cnblogs.com/xiangtingshen/p/12083359.html