QT中学习Opengl---(摄像机2)

前言:

本文的代码是 LearnOpenGL 中对应代码,这里提供学习,大家喜欢的可去官方网站去看看:

 LearnOpenGL-CNhttps://learnopengl-cn.readthedocs.io/zh/latest/

 本章讲解摄像机的移动。

欧拉角

      欧拉角是表示3D空间中可以表示任何旋转的三个值, 由莱昂哈德·欧拉在18世纪提出。 有三种
欧拉角: 俯仰角(Pitch)、 偏航角(Yaw)和滚转角(Roll), 下面的图片展示了它们的含义:

 下面看看添加鼠标,键盘,视角的变化吧。

代码部分

 顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
        gl_Position =projection*view*model* vec4(aPos, 1.0);
        TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

片段着色器:

#version 330 core
out vec4 FragColor;

in vec2 TexCoord;

// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;

void main()
{
        // linearly interpolate between both textures (80% container, 20% awesomeface)
        FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
        //FragColor =texture(texture2,TexCoord);
}

源码部分:

#ifndef BKQOPENGLW_H
#define BKQOPENGLW_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QTimer>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QPoint>
class BKQOpenglW : public QOpenGLWidget, QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    enum Shape{None,Rect,circle,Triangle};
    explicit BKQOpenglW(QWidget *parent = nullptr);
    ~BKQOpenglW();
    void drawShapes(Shape shape);
    void setWireFrame(bool b);
protected:
    //设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
    virtual void initializeGL() override;
    //渲染OpenGL场景,每当需要更新小部件时使用
    virtual void resizeGL(int w, int h) override;
    //设置OpenGL视口、投影等,每当尺寸大小改变时调用
    virtual void paintGL() override;
    //键盘操作重载Qt的事件处理
    virtual void keyPressEvent(QKeyEvent *event) override;
    //鼠标操作,重载Qt的事件处理
    void mousePressEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void wheelEvent(QWheelEvent *event) override;
private:
    //计算
    void calculateCamera();
    QMatrix4x4 getViewMatrix();
signals:

public slots:

private:
    unsigned int VBO, VAO,EBO;
    Shape m_Shape;
    QOpenGLShaderProgram shaderProgram;
    unsigned int texture;
    QOpenGLTexture *pTexture;
    QOpenGLTexture *pTexture2;

    QTimer timer;
    int rotate{ 0 };

    //鼠标位置
    QPoint mousePos;
    QVector3D cameraPos{ 0.0f, 0.0f, 3.0f };
    QVector3D cameraFront{ 0.0f, 0.0f, -1.0f };
    QVector3D cameraUp{ 0.0f, 1.0f, 0.0f };
    QVector3D cameraRight{ 1.0f, 0.0f, 0.0f };
    //Euler Angles
    //偏航角如果是0.0f,指向的是 x轴正方向,即右方向,所以向里转90度,初始方向指向z轴负方向
    float eulerYaw{ -90.0f }; //偏航角,绕y左右转
    float eulerPitch{ 0.0f }; //俯仰角,绕x上下转
    //Camera options
    float cameraSpeed{ 0.5f }; //移动速度
    float cameraSensitivity{ 0.1f }; //鼠标拖动灵敏度
    float projectionFovy{ 45.0f }; //透视投影的fovy参数,视野范围


};

#endif // BKQOPENGLW_H

对应cpp

#include "bkqopenglw.h"
#include<iostream>
#include <QDebug>
#include <QSurfaceFormat>
#include <cmath>
#include <QtMath>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#if 0
float vertices[] = {
        // positions          // colors           // texture coords
         0.8f,  0.8f, 0.0f,   1.0f, 0.0f, 0.0f,   2.0f, 2.0f, // top right
         0.8f, -0.8f, 0.0f,   0.0f, 1.0f, 0.0f,   2.0f, 0.0f, // bottom right
        -0.8f, -0.8f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.8f,  0.8f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 2.0f  // top left
    };

#endif

//顶点数据(盒子六个面,一个面两个三角)
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
};


unsigned int indices[] = {  // note that we start from 0!
    0, 1, 3,  // first Triangle
    1, 2, 3   // second Triangle
};


//绘制多个盒子
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)
};


BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
//    QSurfaceFormat fmt = format();
//    fmt.setRenderableType(QSurfaceFormat::OpenGL);
//    fmt.setProfile(QSurfaceFormat::CoreProfile);
    fmt.setVersion(3, 3);
//    //当启用多重采样时,将每个像素的首选样本数设置为numSamples
//    fmt.setSamples(4);
//    setFormat(fmt);


    connect(&timer,&QTimer::timeout,this,[this](){
            rotate+=2;
            if(isVisible()){
                update();
            }
        });
        timer.setInterval(50);
     //弧度转换
     calculateCamera();

}

BKQOpenglW::~BKQOpenglW()
{
    makeCurrent();
    glDeleteVertexArrays(1,&VAO);
    glDeleteBuffers(1,&VBO);
    doneCurrent();
}

void BKQOpenglW::drawShapes(BKQOpenglW::Shape shape)
{
    m_Shape = shape;
    update();
}

void BKQOpenglW::setWireFrame(bool b)
{
    makeCurrent();
    if(b)
    {
       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }
    else {
       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }
    update();
    doneCurrent();
}

void BKQOpenglW::initializeGL()
{
    initializeOpenGLFunctions();

    //    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,vertexShaderSource);
    //    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,fragmentShaderSource);
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/shader.vs");
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/shader.fs");
    shaderProgram.link();
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //绑定ebo
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    // texture coord attribute
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    //绑定纹理
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    pTexture = new QOpenGLTexture(QImage(":/images/images/brickwall.jpg").mirrored());
    pTexture2 = new QOpenGLTexture(QImage(":/images/images/awesomeface.png").mirrored());
    shaderProgram.bind();
    shaderProgram.setUniformValue("texture1",0);
    shaderProgram.setUniformValue("texture2",1);
    //默认为GL_REPEAT 重复 GL_MIRRORED_REPEAT镜像  GL_CLAMP_TO_EDGE 边缘拉伸 GL_CLAMP_TO_BORDER 超出部分使用用户定义
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT);	// we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT);


    QMatrix4x4 projection; //透视投影
    //坐标到达观察空间之后,我们需要将其投影到裁剪坐标。
    //裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上
    //参数1:指定视景体的视野的角度
    //参数2:指定你的视景体的宽高比
    //参数3:指定观察者到视景体的最近的裁剪面的距离(正数)
    //参数4:指定观察者到视景体最远的裁剪面距离(正数)
    projection.perspective(45.0f, 1.0f * width() / height(), 0.1f, 100.0f);
    shaderProgram.setUniformValue("projection", projection);
    shaderProgram.release();

    timer.start();

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0);

}

void BKQOpenglW::resizeGL(int w, int h)
{
       glViewport(0,0,w,h);
}

void BKQOpenglW::paintGL()
{

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.2f, 0.3f, 0.3f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


    shaderProgram.setUniformValue("view", getViewMatrix());


    shaderProgram.bind();
    glBindVertexArray(VAO);
    switch (m_Shape) {
    case Triangle:
        glDrawArrays(GL_TRIANGLES,0,3);
        break;
    case Rect:
        pTexture->bind(0);
        pTexture2->bind(1);

        for (unsigned int i = 0; i < 10; i++) {
               //计算模型矩阵
               QMatrix4x4 model;
               //平移
               model.translate(cubePositions[i]);
               //这样每个箱子旋转的速度就不一样
               float angle = (i + 1.0f) * rotate;
               //旋转
               model.rotate(angle, QVector3D(1.0f, 0.3f, 0.5f));
               //传入着色器并绘制
               shaderProgram.setUniformValue("model", model);
               glDrawArrays(GL_TRIANGLES, 0, 36);
           }
        break;
    default:
        break;
    }

}

void BKQOpenglW::keyPressEvent(QKeyEvent *event)
{
     event->accept();
     //横向是移动,不是绕0点
     switch (event->key()) {
     case Qt::Key_W: //摄像机往上,场景往下
         cameraPos -= QVector3D::crossProduct(cameraFront, cameraRight).normalized() * cameraSpeed;
         break;
     case Qt::Key_S: //摄像机往下,场景往上
         cameraPos += QVector3D::crossProduct(cameraFront, cameraRight).normalized() * cameraSpeed;
         break;
     case Qt::Key_A: //摄像机往左,场景往右
         cameraPos -= QVector3D::crossProduct(cameraFront, cameraUp).normalized() * cameraSpeed;
         break;
     case Qt::Key_D: //摄像机往右,场景往左
         cameraPos += QVector3D::crossProduct(cameraFront, cameraUp).normalized() * cameraSpeed;
         break;
     case Qt::Key_E: //远
         cameraPos -= cameraFront * cameraSpeed;
         break;
     case Qt::Key_Q: //近
         cameraPos += cameraFront * cameraSpeed;
         break;
     default:
         break;
     }
     update();

}

void BKQOpenglW::mousePressEvent(QMouseEvent *event)
{
    event->accept();
    mousePos = event->pos();
}

void BKQOpenglW::mouseReleaseEvent(QMouseEvent *event)
{
     event->accept();
}

void BKQOpenglW::mouseMoveEvent(QMouseEvent *event)
{
    event->accept();
    int x_offset = event->pos().x()-mousePos.x();
    int y_offset = event->pos().y()-mousePos.y();
    mousePos = event->pos();
    //y轴的坐标是从下往上,所以相反
    //我这里移动的是摄像机,所以场景往相反方向动
    eulerYaw += x_offset*cameraSensitivity;
    eulerPitch -= y_offset*cameraSensitivity;

    if (eulerPitch > 89.0f)
        eulerPitch = 89.0f;
    else if (eulerPitch < -89.0f)
        eulerPitch = -89.0f;
    calculateCamera();
    update();
}

void BKQOpenglW::wheelEvent(QWheelEvent *event)
{
    event->accept();
        //fovy越小,模型看起来越大
    if(event->delta() < 0){
        //鼠标向下滑动为-,这里作为zoom out
        projectionFovy += cameraSpeed;
        if(projectionFovy > 90)
            projectionFovy = 90;
    }else{
        //鼠标向上滑动为+,这里作为zoom in
        projectionFovy -= cameraSpeed;
        if(projectionFovy < 1)
            projectionFovy = 1;
    }
    update();

}

void BKQOpenglW::calculateCamera()
{
    const float yaw = qDegreesToRadians(eulerYaw);
    const float pitch = qDegreesToRadians(eulerPitch);
    QVector3D front;
    front.setX(std::cos(yaw) * std::cos(pitch));
    front.setY(std::sin(pitch));
    front.setZ(std::sin(yaw) * std::cos(pitch));
    cameraFront = front.normalized();
}

QMatrix4x4 BKQOpenglW::getViewMatrix()
{
    QMatrix4x4 view; //观察矩阵
    view.lookAt(cameraPos, cameraPos+cameraFront, cameraUp);
    return view;
}

后面的话

     人生需要坚持下去,时间也会一点点给你回报,几个月没有更新了,以后要更加勤快。加油! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值