IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 《Qt-OpenGL系列编程》课程学习记录(4):OpenGL着色器语言(GLSL) -> 正文阅读

[游戏开发]《Qt-OpenGL系列编程》课程学习记录(4):OpenGL着色器语言(GLSL)

in 关键字定义的变量

in type in_variable_name; 

表明此变量来自OpenGL管线。当前要定义一个变量保存它的值。

out 关键字定义的变量

out type out_variable_name; 

表明此变量是要传到别的着色器的变量。

uniform 关键字定义的变量

uniform type uniform_name; 

表明是可以由CPU和GPU都可以访问的变量。

顶点属性数量限制

OpenGL确保至少有16个包含4分量的顶点属性可用,但是有些硬件或许允许更多的顶点属性。

能声明的顶点属性数量的上限可以通过下面的代码获取:

    int nrAttributes;
    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
    qDebug()<<"nrAttributes = "<<nrAttributes;//>=16

基本数据类型

int、float、double、uint、bool。

容器数据类型

1、向量:

  • vecn:n 个 float 的默认向量
  • bvecn:n 个 bool 的向量
  • ivecn:n 个 int 的向量
  • uvecn:n 个 uint 的向量
  • dvecn:n 个 double 的向量

2、矩阵

向量的重组

vec2 vect = vec2(0.5, 0.7); 
vec4 result = vec4(vect, 0.0, 0.0); //(0.5,0.7,0.0,0.0)
vec4 otherResult = vec4(result.xyz, 1.0);//(0.5,0.7,0.0,1.0)
vec4 otherResult2 = vec4(result.xxx, 1.0);//(0.5,0.5,0.5,1.0)

变量的输入输出

  1. 在发送方着色器中声明一个输出
  2. 在接收方着色器中声明一个类似的输入
  3. 当类型和名字都一致,OpenGL把变量链接到一起(在链接程序对象时完成)

//顶点着色器 shapes.vert
#version 450 core
layout (location = 0) in vec3 aPos;
out vec4 vertexColor;
void main()
{
    gl_Position = vec4(aPos, 1.0);
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0);
}
//片段着色器 shapes.frag
#version 450 core
out vec4 FragColor;
in vec4 vertexColor;

void main()
{
    FragColor = vertexColor;
}
#include "widget.h"
#include <QOpenGLShaderProgram>

unsigned int VBO, VAO,EBO;
float vertices[] =
{
    0.5f, 0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f,
    -0.5f, 0.5f, 0.0f
};

unsigned int indices[] =
{
    0, 1, 3,
    1, 2, 3
};

QOpenGLShaderProgram shaderProgram;

Widget::Widget(QWidget *parent) : QOpenGLWidget(parent)
{
}

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

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

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

    //告知显卡如何解析缓冲里的属性值
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
    //开启VAO管理的第一个属性值
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shapes.vert");
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shapes.frag");
    if(!shaderProgram.link())
        qDebug()<<"ERR:"<<shaderProgram.log();

    // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glBindVertexArray(0);
}

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

    shaderProgram.bind();
    glBindVertexArray(VAO);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
}

layout (location = 0)的含义

#version 450 core
layout (location = 0) in vec3 aPos;
out vec4 vertexColor;
void main()
{
    gl_Position = vec4(aPos, 1.0);
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0);
}

顶点着色器的顶点数据来自用户的配置(来自CPU,要将它传到GPU)。

location 指定CPU上配置的顶点的索引(上面也说了OpenGL保证至少可配置16个变量)。

这里的:layout (location = 0) 并不是必须的,前一节的代码,顶点着色器写成这样:

#version 450 core
in vec3 aPos;
out vec4 vertexColor;
void main()
{
    gl_Position = vec4(aPos, 1.0);
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0);
}

代码里的:

上面的 0 也是指第0个配置数据的索引。

当想知道配置的变量的索引时,可以调用 attributeLocation()函数:

    shaderProgram.bind();
    GLint posLocation = shaderProgram.attributeLocation("aPos");
    qDebug()<<"posLocation = "<<posLocation;//0

除了在顶点着色器的代码指定变量的索引,也可以在其他代码指定:

    shaderProgram.bindAttributeLocation("aPos",2);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
    glEnableVertexAttribArray(2);

将变量 aPos 绑定为第3个变量,并启用变量,效果和之前一样。

uniform

使用 uniform 定义的变量全局的,可以被任意着色器程序在任意阶段访问。

也就是可以定义一个CPU、GPU都能使用的变量。

//片段着色器shapes.frag
#version 450 core
out vec4 FragColor;
uniform vec4 ourColor;
void main()
{
    FragColor = ourColor;
}
#include "widget.h"
#include <QOpenGLShaderProgram>
#include <QTimer>
#include <QTime>

unsigned int VBO, VAO,EBO;
float vertices[] =
{
    0.5f, 0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f,
    -0.5f, 0.5f, 0.0f
};

unsigned int indices[] =
{
    0, 1, 3,
    1, 2, 3
};

QOpenGLShaderProgram shaderProgram;

Widget::Widget(QWidget *parent) : QOpenGLWidget(parent)
{
    QTimer * timer = new QTimer(this);
    connect(timer,&QTimer::timeout,[this]
    {
        makeCurrent();

        int timeValue = QTime::currentTime().second();
        float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
        shaderProgram.setUniformValue("ourColor",0.0f, greenValue, 0.0f, 1.0f);

        doneCurrent();
        update();
    });
    timer->start(345);
}

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

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

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

    //告知显卡如何解析缓冲里的属性值
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
    //开启VAO管理的第-个属性值
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shapes.vert");
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shapes.frag");
    if(!shaderProgram.link())
        qDebug()<<"ERR:"<<shaderProgram.log();

    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glBindVertexArray(0);
}

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

    shaderProgram.bind();
    glBindVertexArray(VAO);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
}

一个把颜色数据加进顶点数据的例子

首先,顶点着色器是OpenGL管线的第一个着色器,接收来自CPU配置的数据:

//顶点着色器 shapes.vert
#version 450 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
out vec3 ourColor;
void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);
    ourColor = aColor;
}

接收索引为0的位置数据、索引为1的颜色数据,处理后输出 ourColor 变量。

片段着色器收到了?ourColor 传过来的颜色数据。

//片段着色器 shapes.frag
#version 450 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
    FragColor = vec4(ourColor, 1.0f);
}
#include "widget.h"
#include <QOpenGLShaderProgram>
#include <QTimer>
#include <QTime>

unsigned int VBO, VAO,EBO;
float vertices[] =
{   //四个点的位置          四个点的颜色
    0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 0.0f,
    0.5f, -0.5f, 0.0f,      0.0f, 1.0f, 0.0f,
    -0.5f, -0.5f, 0.0f,     0.0f, 0.0f, 1.0f,
    -0.5f, 0.5f, 0.0f,      0.5f, 0.5f, 0.5f,
};

unsigned int indices[] =
{
    0, 1, 3,
    1, 2, 3
};

QOpenGLShaderProgram shaderProgram;

Widget::Widget(QWidget *parent) : QOpenGLWidget(parent)
{
}

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

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

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

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

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

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

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shapes.vert");
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shapes.frag");
    if(!shaderProgram.link())
        qDebug()<<"着色器程序编译错误信息:"<<shaderProgram.log();

    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glBindVertexArray(0);
}

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

    shaderProgram.bind();
    glBindVertexArray(VAO);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
}

传入4个点的颜色,OpenGL会在点之间做差值,从而形成渐变效果。

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-05-25 11:44:00  更:2022-05-25 11:44:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 11:14:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码