1、QOpenGLShaderProgram
//使用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();
可以替代直接用GL库写。
上面可以选择添加文件,也可以选择添加code
2、GLSL: OpenGL Shading Language
上述使用到了shader程序,我们先来了解下shader程序。
2.1 shader中的in和out
一个shader程序的典型结构:
2.2 向量与类型
我们能声明的顶点属性数量是有上限的,可以通过下面的代码获取:
向量允许一些有趣而灵活的分量选择方式,叫做重组(Swizzling)
- 在发送方着色器中声明一个输出
- 在接收方着色器中声明一个类似的输入
- 当类型和名字都一致,OpenGL将把变量链接到一起(在链接程序对象时完成)
eg:
2.3 属性与lauout
2.4 uniform
Uniform:另一种从CPU的应用,向GPU中的着色器发送数据的方式
- Uniform是全局的(Global),可以被任意着色器程序在任意阶段访问
如果声明了一个uniform却没用过,编译器会默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误,切记!
2.5 更多属性
把顶点数据加进顶点数据中
举例:
float vertices[] =
{
//positions //colors
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[] = //note that we start from 0!
{
0, 1, 3,//第一个三角形
1, 2, 3 // 第二个三角形
};
//访问着色器里面属性的位置
m_shaderProgram.bind();
GLint posLocation = m_shaderProgram.attributeLocation("aPos");//询问着色器里面变量aPos顶点信息的属性位置
GLint colorLocation = m_shaderProgram.attributeLocation("aColor");//询问着色器里面变量ourColor颜色信息的属性位置
//告知显卡如何解析缓冲里的顶点属性值
glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
//告知显卡如何解析缓冲里的颜色属性值
glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
//开启VAO管理的顶点属性值
glEnableVertexAttribArray(posLocation);
//开启VAO管理的颜色属性值
glEnableVertexAttribArray(colorLocation);
片段着色器shader:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0);
}
顶点着色器shader:
#version 330 core
layout (location = 2) in vec3 aPos;//location属性位置有16个
layout (location = 3) in vec3 aColor;
out vec3 ourColor;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
}