自学内容网 自学内容网

QT中的OpenGL学习------向量

一、线性代数知识

1.1 向量的点乘与叉乘

1.2 矩阵

1.3 旋转、缩放、位移

二、代码实现

#include "openglwidget.h"

unsigned int VBO, VAO, EBO;
float ratio = 0.5;
float vertices[] =
{
    //positions //colors //texture coordinates
    0.3f, 0.3f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,//右上
    0.3f, -0.3f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,//右下
    -0.3f, -0.3f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,//左下
    -0.3f, 0.3f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f//左上
};
//九格
//float vertices[] =
//{
//    //positions //colors //texture coordinates
//    0.9f, 0.9f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f,//右上
//    0.9f, -0.9f, 0.0f, 0.0f, 1.0f, 0.0f, 2.0f, -1.0f,//右下
//    -0.9f, -0.9f, 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, -1.0f,//左下
//    -0.9f, 0.9f, 0.0f, 0.5f, 0.5f, 0.5f, -1.0f, 2.0f//左上
//};
unsigned int indices[] = //note that we start from 0!
{
    0, 1, 3,//第一个三角形
    1, 2, 3 // 第二个三角形
};

OpenGLWidget::OpenGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
    m_timer = new QTimer;
    m_timer->start(100);
    connect(m_timer, &QTimer::timeout, this, [=](){
        update();
    });
}

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

void OpenGLWidget::drawShape(Shape shape)
{
    m_shape = shape;
    update();
}

void OpenGLWidget::setWireframe(bool wireframe)
{
    makeCurrent();
    if (wireframe)
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }
    else
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }
    update();
    doneCurrent();
}

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

    //使用QT封装的着色器
    bool success;
    m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/shapes.vert");//顶点着色器
    m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/shapes.frag");//片段着色器
    success = m_shaderProgram.link();//连接到着色器
    if(!success)
        qDebug() << "ERR:" << m_shaderProgram.log();

    //创建VBO和VAO对象,并赋予ID
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    //绑定VBO和VAO对象
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    //为当前绑定到target的缓冲区对象创建一个新的数据存储
    //如果data不是NULL,则使用来自此指针的数据初始化数据存储
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //访问着色器里面属性的位置
    m_shaderProgram.bind();
    GLint posLocation = m_shaderProgram.attributeLocation("aPos");//询问着色器里面变量aPos顶点信息的属性位置
//    GLint colorLocation = m_shaderProgram.attributeLocation("aColor");//询问着色器里面变量ourColor颜色信息的属性位置
    GLint textureLocation = m_shaderProgram.attributeLocation("aTextureCoordinates");

    //告知显卡如何解析缓冲里的顶点属性值
    glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
//    //告知显卡如何解析缓冲里的颜色属性值
//    glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    //告知显卡如何解析缓冲里的纹理属性值
    glVertexAttribPointer(textureLocation, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));

    //开启VAO管理的顶点属性值
    glEnableVertexAttribArray(posLocation);
//    //开启VAO管理的颜色属性值
//    glEnableVertexAttribArray(colorLocation);
    //开启VAO管理的纹理属性值
    glEnableVertexAttribArray(textureLocation);

    //EBO创建与绑定
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //纹理
    textureWall = new QOpenGLTexture(QImage(":/imags/imag/1.jpg").mirrored());
    textureLe = new QOpenGLTexture(QImage(":/imags/imag/2.jpg").mirrored());
    textureSmall = new QOpenGLTexture(QImage(":/imags/imag/3.jpg").mirrored());
    texturePJ = new QOpenGLTexture(QImage(":/imags/imag/4.jpg").mirrored());
    //设置纹理单元,纹理单元有16个
    m_shaderProgram.bind();
    m_shaderProgram.setUniformValue("textureWall", 0);
    m_shaderProgram.setUniformValue("textureLe", 1);
    m_shaderProgram.setUniformValue("textureSmall", 2);
    m_shaderProgram.setUniformValue("texturePJ", 3);

    //设置渐远纹理
    texturePJ->generateMipMaps();

    //纹理绑定
    texturePJ->bind(3);
    textureSmall->bind(2);
    textureLe->bind(1);
    textureWall->bind(0);
    /**********在画之前设置纹理参数**********/
//    float borderColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
    //复制,qt默认复制
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

    //镜像,T和S对应X和Y轴
//  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
//  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

    //纹理坐标约束到0到1,超出部分边缘拉伸
//  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

    //超出坐标指定边缘色
//  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
//  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
//  glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

    //纹理像素(过滤),
    //GL_NEAREST高新能低质量/GL_LINEAR高质量低性能,
    //这里设置缩小像素,放大线性
    //GL_LINEAR_MIPMAP_NEAREST、GL_LINEAR_MIPMAP_LINEAR渐远纹理
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    /*************************************/

    //VAO和VBO绑定为0,相当于释放休息
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

void OpenGLWidget::resizeGL(int w, int h)
{
    Q_UNUSED(h)
    Q_UNUSED(w)
}

void OpenGLWidget::paintGL()
{
    QMatrix4x4 matrix;
    unsigned int time = QTime::currentTime().msec();
    //先旋转再位移,图片在固定位置旋转
    //先位移再旋转,图片围着一个地方转
    //具体参考线性代数矩阵知识
    matrix.translate(0.5, -0.5, 0);//位移
    matrix.rotate(time, 0.0f, 0.0f, 1.0f);//旋转

    //red:0.0f无色,1.0f全红
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    m_shaderProgram.bind();//绑定可以理解为使用它
    m_shaderProgram.setUniformValue("ratio", ratio);
    glBindVertexArray(VAO);

    /*
        * EBO解绑时VAO会记录,如果EBO上面解绑了,即
        * glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
        * 那么glDrawElements画要素需要索引,即
        * glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &indices)
        * VBO不存在这个问题,VAO不存储VBO的绑定函数调用
    */
    switch (m_shape)
    {
    case Rect:
        //纹理绑定
//        texturePJ->bind(3);
//        textureSmall->bind(2);
        textureLe->bind(1);
        textureWall->bind(0);

        //旋转设置
        m_shaderProgram.setUniformValue("theMatrix", matrix);
        //图形绘画
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);

        //画第二个图
        matrix.setToIdentity();//变回单位向量,不受前面设置的影响
        matrix.translate(-0.5, 0.5, 0);//右上角
        matrix.scale(fabs(sin(time)));//放大缩小,abs取绝对值,f浮点型
        m_shaderProgram.setUniformValue("theMatrix", matrix);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);

        break;
    default:
        break;
    }
}

void OpenGLWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case Qt::Key_Up:
        ratio += 0.1;
        break;
    case Qt::Key_Down:
        ratio -= 0.1;
        break;
    default:
        break;
    }
    if(ratio>1) ratio = 1;
    if(ratio<0) ratio = 0;

    m_shaderProgram.bind();
    m_shaderProgram.setUniformValue("ratio", ratio);
    update();
}



#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H

#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QKeyEvent>
#include <QMatrix4x4>
#include <QTime>
#include <QTimer>
#include <QtMath>

class OpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    enum Shape {None, Rect, Circle, Triangle};
    explicit OpenGLWidget(QWidget* parent = nullptr);
    ~OpenGLWidget();

    void drawShape(Shape shape);
    void setWireframe(bool wireframe);

protected:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();
    virtual void keyPressEvent(QKeyEvent *event);

signals:

private:
    Shape m_shape;
    QOpenGLShaderProgram m_shaderProgram;
    QOpenGLTexture *textureWall;
    QOpenGLTexture *textureLe;
    QOpenGLTexture *textureSmall;
    QOpenGLTexture *texturePJ;
    QTimer *m_timer;
};

#endif // OPENGLWIDGET_H
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TextureCoordinates;
uniform sampler2D textureWall;
uniform sampler2D textureLe;
uniform sampler2D textureSmall;
uniform sampler2D texturePJ;
uniform float ratio;
void main()
{
    //原图混合rgb颜色
//    FragColor = texture(textureWall, TextureCoordinates)*vec4(1.0, 1.0, 0.0, 0.2);
    //多张图融合
    FragColor = mix(texture(textureWall, TextureCoordinates), texture(textureLe, TextureCoordinates), ratio);
    //纹理
//    FragColor = texture(texturePJ, TextureCoordinates);
}
#version 330 core
layout (location = 2) in vec3 aPos;//location属性位置有16个
layout (location = 3) in vec3 aColor;
layout (location = 1) in vec2 aTextureCoordinates;
out vec3 ourColor;
out vec2 TextureCoordinates;
uniform mat4 theMatrix;//矩阵
void main()
{
//    gl_Position = vec4(aPos, 1.0);
    gl_Position = theMatrix * vec4(aPos, 1.0);
    ourColor = aColor;
    TextureCoordinates = aTextureCoordinates;
    //图片翻转
//    TextureCoordinates = vec2(1-aTextureCoordinates.s, aTextureCoordinates.t);
}

三、演示视屏

旋转跳跃无极限

四、详细学习资料

自行前往B站观看up主的视频:

4-5练习_哔哩哔哩_bilibili


原文地址:https://blog.csdn.net/MasterPJ/article/details/137818154

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!