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)
变量的输入输出
- 在发送方着色器中声明一个输出
- 在接收方着色器中声明一个类似的输入
- 当类型和名字都一致,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会在点之间做差值,从而形成渐变效果。
|