初始化
void initializeGL() override;
1. 初始化
initializeOpenGLFunctions();
2. 定义或导入着色器语言
//顶点着色器
const char* vertexShaderSource = R"(
#version 450 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos, 1.0);
}
)";
//片元着色器
const char* fragmentShaderSource = R"(
#version 450 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
)";
3. 导入着色器语言并编译
3.1 获取着色器句柄
//获取顶点着色器句柄
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
3.2 将着色器句柄指向源码(将源码加入到OpenGL中)
//arg1:着色器句柄,arg2:所绑定的源码个数, arg3:源码字符串数组,arg4:字符串长度,若为NULL则将字符串视为以NULL结尾的字符串
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
3.3 编译着色器
glCompileShader(vertexShader);
3.4 检查是否成功编译
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
qDebug() << "Vertex shader compilation failed: " << infoLog;
}
4. 将各个管线上的程序连接成整个程序
//着色器程序获取句柄
GLuint shaderProgram = glCreateProgram();
//指定程序句柄与哪些着色器句柄连接
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
//程序连接
glLinkProgram(shaderProgram);
//判断是否出现连接错误
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
qDebug() << "Shader program linking failed: " << infoLog;
}
5. 删除着色器
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
循环绘制
void paintGL() override;
绘制数据与功能设置
1. 清空缓冲区
//设置清空所刷新的颜色
glClearColor(1.0, 1.0, 1.0, 1.0);
//清空颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
2. 导入顶点信息
//定义绘制图形的顶点
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
3. 设置着色器程序
//使用着色器程序
glUseProgram(shaderProgram);
4. 获取VAO和VBO
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
5. 将VAO和VBO绑定到上下文
//当前 顶点数组对象:NULL 顶点缓存对象:NULL
glBindVertexArray(VAO);
//当前 顶点数组对象:VAO 顶点缓存对象:NULL
//在当前上下文中绑定顶点缓存对象产生层级关系 VAO -> VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//当前 顶点数组对象:VAO 顶点缓存对象:VBO
6. 将顶点数据添加到OpenGL中
//在GPU中开辟内存,创建缓冲区对象,并将数据拷贝到对象中
//因为当前顶点缓存对象上下文为VBO,所以存在层级关系VBO -> vertices
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
7. 设置解析数据的方式,并定义将该数据流入哪个索引
//arg1:流入哪个索引,此索引与着色器中layout(location = %%)中的数字相对应
//arg2, arg3:定义一次读取数据的长度
//arg4:是否进行归一化
//arg5:定义数据之间的间隔
//arg6:数据初始偏移量
//数据读取方式 根据定义读取 [arg6 + arg5 * k, arg6 + arg5 * k + arg2 * arg3)中的数据,arg4决定数据是否归一化,最后将数据输出到着色器中arg1索引接口
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
8. 连通数据之间的读取方式
glEnableVertexAttribArray(0);
9. 清空上下文状态
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
绘制
1. 设置VAO上下文
glBindVertexArray(VAO);
2. 绘制
//按照绘制三角形的方式,从第0个顶点开始,绘制3个顶点,
glDrawArrays(GL_TRIANGLES, 0, 3);
收尾
1. 删除VAO和VBO
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
完整代码
#include <QApplication>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QDebug>
class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Core
{
public:
void initializeGL() override
{
initializeOpenGLFunctions();
// 创建和编译着色器
const char* vertexShaderSource = R"(
#version 450 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos, 1.0);
}
)";
const char* fragmentShaderSource = R"(
#version 450 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
)";
GLuint vertexShader, fragmentShader;
GLint success;
char infoLog[512];
// 顶点着色器
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
qDebug() << "Vertex shader compilation failed: " << infoLog;
}
// 片段着色器
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
qDebug() << "Fragment shader compilation failed: " << infoLog;
}
// 着色器程序
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
qDebug() << "Shader program linking failed: " << infoLog;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void paintGL() override
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
// 使用着色器程序
glUseProgram(shaderProgram);
// 绘制三角形
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
GLuint VAO, VBO;
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, 3 * sizeof(GLfloat)
, (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
}
private:
GLuint shaderProgram;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyOpenGLWidget widget;
widget.resize(800, 600);
widget.show();
return app.exec();
}