《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会在点之间做差值,从而形成渐变效果。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用OpenGLQt绘制立方体的示例代码: ```cpp #include <QtGui/QOpenGLFunctions> #include <QtGui/QOpenGLShaderProgram> #include <QtGui/QOpenGLVertexArrayObject> #include <QtGui/QOpenGLBuffer> class CubeRenderer : public QOpenGLFunctions { public: CubeRenderer() {} void initialize() { initializeOpenGLFunctions(); m_program = new QOpenGLShaderProgram(); m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.glsl"); m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.glsl"); m_program->link(); m_vao = new QOpenGLVertexArrayObject(); m_vao->create(); m_vao->bind(); float vertices[] = { // Front face -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // Back face -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, // Top face -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, // Bottom face -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, // Right face 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, // Left face -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f }; m_vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); m_vbo->create(); m_vbo->bind(); m_vbo->allocate(vertices, sizeof(vertices)); m_program->enableAttributeArray(0); m_program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 3 * sizeof(float)); m_vao->release(); m_vbo->release(); glEnable(GL_DEPTH_TEST); } void render() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_program->bind(); m_vao->bind(); glDrawArrays(GL_QUADS, 0, 24); m_vao->release(); m_program->release(); } private: QOpenGLShaderProgram *m_program; QOpenGLVertexArrayObject *m_vao; QOpenGLBuffer *m_vbo; }; // 在你的OpenGL窗口中的绘制函数中调用以下代码: CubeRenderer cubeRenderer; cubeRenderer.initialize(); cubeRenderer.render(); ``` 在此示例代码中,我们使用了OpenGL的立方体顶点数据和一个简单的着色器程序来绘制立方体。我们还使用了QtOpenGL函数、着色器程序、顶点数组对象和缓冲区对象来管理OpenGL状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值