QT中学习Opengl---(GLSL简单的使用)

2023-11-15

前言:

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

https://learnopengl-cn.readthedocs.io/zh/latest/https://learnopengl-cn.readthedocs.io/zh/latest/本章简单讲解GLSL 中的简单使用,详细知识点请查阅对应书籍

 GLSL:

   着色器是使用一种叫GLSL的类C语言写成的。 GLSL是为图形计算量身定制的, 它包含针对向
量和矩阵操作的有用特性。

比如我们顶点着色器写成:

#version 330 core
layout (location = 0) in vec3 position; // 位置变量的属性为0
out vec4 vertexColor; // 为片段着色器指定一个颜色输出
void main()
{
gl_Position = vec4(position, 1.0); // 把一个vec3作为vec4的构造器的参数
vertexColor = vec4(0.5f, 0.0f, 0.0f, 1.0f); // 把输出颜色设置为暗红色
}

这里我们看到有layout  out ,其实我们常用的就是 in out  、layout、uniform这几个,下面我给你们讲下基本情况,大家也就了解了。

in 与 out 

在shader.vs 文件下:

#version 330 core
layout (location = 0) in vec3 position;
out vec4 vertexColor;
void main()
{
    gl_Position = vec4(position.x, position.y, position.z, 1.0);
    vertexColor = vec4(0.5f,0.0f,0.0f,1.0f);
}

在shader.fs 文件下:

#version 330 core
out vec4 color;
in vec4 vertexColor;
void main()
{
    color = vertexColor;//RGBA
}

我们可以看到里面都有个变量vertexColor,在顶点着色器中输出,然后在片段着色器接受,然后在给颜色。

输出结果:

 如何理解in 与 out 呢:

 如图,in 就是给这个着色器的值,out 就是送出去的值。这下,你懂了吧。

全部代码:

#ifndef BKQOPENGLW_H
#define BKQOPENGLW_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
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:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();

signals:

public slots:

private:
unsigned int VBO, VAO;
Shape m_Shape;
QOpenGLShaderProgram shaderProgram;
};

#endif // BKQOPENGLW_H

cpp

#include "bkqopenglw.h"
#include<iostream>
const float vertices[] = {
    -0.5f, -0.5f, 0.0f, // left
     0.5f, -0.5f, 0.0f, // right
     0.0f,  0.5f, 0.0f  // top
};

//顶点着色器
const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";
//片段着色器
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
{

}

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();
    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);

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

    // 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);


//    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();
    //链接着色器

}

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

void BKQOpenglW::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    shaderProgram.bind();
    glBindVertexArray(VAO);
    switch (m_Shape) {
        case Triangle:
            glDrawArrays(GL_TRIANGLES,0,3);
        break;
    default:
        break;
    }

}

layout

我们先看基本标识:

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 aColor;
out vec3 outColor;
void main()
{
    gl_Position = vec4(position.x, position.y, position.z, 1.0);
    outColor = aColor;
}
#version 330 core
out vec4 color;
in vec3 outColor;
void main()
{
    color = vec4(outColor,1.0f);//RGBA
}

 这里有location  = 0,1.这里就是对应变量的编号。比如我想把顶点写成

float vertices[] = {
       // positions         // colors
        0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // bottom right
       -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  // bottom left
        0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // top

   };

前边是位置,后面是颜色值,那我们要告诉gpu改如何操作,于是下面代码你就懂了:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);

第一参数就是对应的location,然后最后一个是偏移量。这下你懂了吧。

int nPos =  shaderProgram.attributeLocation("position");
glVertexAttribPointer(nPos, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
glEnableVertexAttribArray(nPos);

我们使用qt中找到对应的pos值也是可以的 。

输出结果:

 cpp代码:

#include "bkqopenglw.h"
#include<iostream>
float vertices[] = {
       // positions         // colors
        0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // bottom right
       -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,  // bottom left
        0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f   // top

   };


BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
{

}

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);

    int nPos =  shaderProgram.attributeLocation("position");
    glVertexAttribPointer(nPos, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
    glEnableVertexAttribArray(nPos);


    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // 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()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    shaderProgram.bind();
    glBindVertexArray(VAO);
    switch (m_Shape) {
        case Triangle:
            glDrawArrays(GL_TRIANGLES,0,3);
        break;
    default:
        break;
    }

}

uniform

  uniform是另一种从CPU应用向GPU着色器发送数据的方式, 但uniform和顶点属性有点不
同。 首先, uniform是全局的(Global)。 这里全局的意思是uniform变量必须在所有着色器程序
对象中都是独一无二的, 它可以在着色器程序的任何着色器任何阶段使用。 第二, 无论你把
uniform值设置成什么, uniform会一直保存它们的数据, 直到它们被重置或更新。

 我们先看基本标识:

#version 330 core
out vec4 color;
uniform vec4 vertexColor;
void main()
{
    color = vertexColor;//RGBA
}
#version 330 core
layout (location = 0) in vec3 position;
void main()
{
    gl_Position = vec4(position.x, position.y, position.z, 1.0);

}

然后我们在代码中写到:

    shaderProgram.bind();
    shaderProgram.setUniformValue("vertexColor",0.5f,0.0f,0.0f,1.0f);

这个是qt提供的类使用的方法,原生方式:

    /*
        opengl 基本写法
        shaderProgram 为glCreateProgram() 返回值  这里可以调用这个shaderProgram.programId() 可以利用
    int vertexColorLocation = glGetUniformLocation(shaderProgram, "vertexColor");
    glUniform4f(vertexColorLocation, 0.5f, 0.0f, 0.0f, 1.0f);
    */
   GLuint id = shaderProgram.programId();
    int vertexColorLocation = glGetUniformLocation(id, "vertexColor");
   glUniform4f(vertexColorLocation, 0.5f, 0.0f, 0.0f, 1.0f);

这里的id 就是你glCreateProgram()返回的值,原生态你要创建的链接器id

然后修改对应的数据:

输出结果:

 全部代码:

#include "bkqopenglw.h"
#include<iostream>
const float vertices[] = {
    -0.5f, -0.5f, 0.0f, // left
     0.5f, -0.5f, 0.0f, // right
     0.0f,  0.5f, 0.0f  // top
};

BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
{

}

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);

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

    // 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);

    /*
        opengl 基本写法
        shaderProgram 为glCreateProgram() 返回值  这里可以调用这个shaderProgram.programId() 可以利用
    int vertexColorLocation = glGetUniformLocation(shaderProgram, "vertexColor");
    glUniform4f(vertexColorLocation, 0.5f, 0.0f, 0.0f, 1.0f);
    */
    shaderProgram.bind();
    shaderProgram.setUniformValue("vertexColor",0.5f,0.0f,0.0f,1.0f);
//    GLuint id = shaderProgram.programId();
//    int vertexColorLocation = glGetUniformLocation(id, "vertexColor");
//    glUniform4f(vertexColorLocation, 0.5f, 0.0f, 0.0f, 1.0f);

    //链接着色器

}

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

void BKQOpenglW::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    shaderProgram.bind();
    //shaderProgram 写法

    glBindVertexArray(VAO);
    switch (m_Shape) {
        case Triangle:
            glDrawArrays(GL_TRIANGLES,0,3);
        break;
    default:
        break;
    }

}

写在后面的话: 

喜欢我博客的小伙伴们,也同时想在qt上学习opengl的伙伴,可以关注与点赞博客,让我们共同进步吧。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT中学习Opengl---(GLSL简单的使用) 的相关文章

随机推荐

  • SpringBoot整合ElasticSearch(二)

    文章目录 es的批量操作 es的重中之重 查询 es与springboot集成 es的批量操作 bulk批量操作 导入数据 分析与创建索引 PUT goods mappings properties title type text anal
  • 如何渲染精美3D PCB图

    简介 现在网上大部分PCB渲染方法都比较麻烦 并且会有丝印不清晰 或者走线与铜皮不显现问题 现在分享一种简单有效的PCB渲染方法 图为渲染效果图 工具或材料 AD keyshot 一个带3D封装图的PCB文件 具体步骤 1 AD端操作 在P
  • 写出你所知道的测试工具,并写出他们的用途和优缺点

    写出你所知道的测试工具 并写出他们的用途和优缺点 Jmeter Apache JMeter是Apache组织开发的基于Java的压力测试工具 Apache jmeter 可以用于对静态的和动态的资源 文件 Servlet Perl脚本 ja
  • XXL-JOB详细说明

    XXL JOB 常见任务调度 单机 Timer ExectorService spring scheduled 分布式 xxl job quartz elastic job 原生定时任务的先天缺陷 XXL JOB简介 由调度中心和执行器组成
  • fabric环境

    1 1环境配置链接 https www jianshu com p 6ef2e8425087 https studygolang com articles 17546 Fabric chaincode测试 开发者模式和单元测试 https
  • 计算机网络 传输层的作用,端口,UDP协议,其他传输层协议

    传输层的作用 传输层定义 IP首部中有一个协议字段 用来标识网络层 IP 的 上一层所采用的是哪一种传输层协议 根据这个字段的协议号 就可以识别IP传 输的数据部分究竟是TCP的内容 还是UDP的内容 同样 传输层的TCP和UDP 为了识别
  • 参与 2023 第一季度官方 Flutter 开发者调查

    Flutter 3 7 已经正式发布 每个季度一次的 Flutter 开发者调查也如约而至 邀请社区的各位成员们填写 调查表链接 https flutter cn urls 2023q1wx 本次调研将会涉及既有的对 Flutter 整体和
  • 【李宏毅深度强化学习笔记】—7、Sparse Reward

    原文链接 https blog csdn net ACL lihan article details 104103873 李宏毅深度强化学习笔记 1 策略梯度方法 Policy Gradient 李宏毅深度强化学习笔记 2 Proximal
  • 24个K8S常用场景使用命令(推荐收藏)!

    kubectl是K8S中的一个命令行工具 主要用于管理和操作K8S集群 kubectl通过向K8S API发送REST请求 允许用户与K8S集群中的各种资源进行交互 列如Pod service Deployment等 kubectl提供了一
  • 【数据结构学习笔记】18:线段树(建树、单点修改、区间查询)

    1 线段树上的操作 push up int u 由子节点的信息去计算父节点的信息 例如两个子节点的区间和 加起来就是父节点表示的区间和 其中u是当前节点编号 表示用u的左右两个子节点来算一下自己这个节点的信息 push down 将父节点的
  • 数据爆炸,Python一键获取阿里法拍的爆款商品数据,并保存到数据库!

    目录 前言 获取数据代码实现 步骤1 获取目标网址 步骤2 向目标网址发送请求并获取响应内容 步骤3 解析网页内容并提取商品信息 步骤4 将商品信息保存到DataFrame中 将商品信息保存到数据库中 步骤1 安装MySQL Connect
  • Spring Boot的自动配置与自定义配置(附配置优先级表)

    相比于Spring MVC Spring Boot省去了繁琐的配置 提供了大部分场景下的默认配置 用户可以在不做任何配置的情况下使用Spring Boot框架进行开发 如果默认的参数并不能满足用户的需求 也只需创建一个配置文件并加上自定义的
  • JetBrains Rider 连接MySQL失败 解决方案

    JetBrains Rider 连接MySQL失败 解决方案 解决JetBrains Rider连接数据库失败 解决方案 设置MySQL时区 time zone 错误界面 Rider 连接mysql 用户名 密码 Port 全都配置好了 点
  • _萌新 web3

  • QFile清空原来文件内容的方法

    QFile清空原来文件内容的方法 Qt 清空文件方法 Qt 清空文件方法 方法一 void DataOperate clearFileInfos QString fileName QFile file fileName file resiz
  • LeetCode1823.找出游戏的胜利者

    共有 n 名小伙伴一起做游戏 小伙伴们围成一圈 按 顺时针顺序 从 1 到 n 编号 确切地说 从第 i 名小伙伴顺时针移动一位会到达第 i 1 名小伙伴的位置 其中 1 lt i lt n 从第 n 名小伙伴顺时针移动一位会回到第 1 名
  • 机器学习之加州房价预测(一)

    加州房价预测实例 任务 基于加州房价数据集建立一个预测模型 使之可以在给定的条件下 预测加州任何地点的房价的中位数 一 定义问题 1 公司要如何利用我的模型 模型的输出将作为另一个机器学习算法的输入 该算法在综合考虑其他因素之后 决定是否值
  • 推荐一本书——《The Scientist and Engineer's Guide to Digital Signal Processing》

    突然在国外的网站上看到一本非常好的数字信号处理的书籍 讲解简介明白 清晰易懂 书籍为免费电子版 地址为 http www dspguide com pdfbook htm
  • day05-编程题

    知识点 方法 题目1 训练 定义一个方法 该方法能够找出两个小数中的较小值并返回 在主方法中调用方法进行测试 训练提示 根据方法的功能描述 方法的参数应该是两个小数 要返回两个小数的较小值 所以返回值类型也是小数类型 解题方案 操作步骤 定
  • QT中学习Opengl---(GLSL简单的使用)

    前言 本文的代码是 LearnOpenGL 中对应代码 这里提供学习 大家喜欢的可去官方网站去看看 https learnopengl cn readthedocs io zh latest https learnopengl cn rea