1 OpenGL 是一个大的状态机。
我的理解是,OpenGL 是C编写的,绘图时需要记录大量的模式,最好的方式就是用状态机的方式。
OpenGL 提供了一些函数继续状态切换,以及对当前状态的修改。
2 OpenGL 是规范。
OpenGL 定义的API,都没有具体的实现。只是个 虚函数 ,具体的实现都是 GPU厂商实现的。
所以,在一开始,需要调用函数:initializeOpenGLFunctions();
//初始化函数,让opengl的函数都指向显卡提供的函数!
initializeOpenGLFunctions();
3 面向 GPU 编程
由于PC的当前架构,对GPU继续编程,没有对CPU方便。( CPU中代码是顺序执行,而GPU是并行)
所以,我们借助 OpenGL 对 GPU 进行编程。
顶点着色器 和 片段着色器 的编程
有一些过程代码,需要编译好后在GPU上运行。比如创建:顶点着色器,和 片段着色器。
所以你会看到这样的代码!program 里面添加的这些 不是C语言而是,GPU上编程用到的一种语言。
program = new QOpenGLShaderProgram(this);
//这段代码是针对着色器的,运行在显卡(GPU)上的一种语言
//用于搬运数据点
// 添加并编译顶点着色器源码。
// QOpenGLShader::Vertex 表示这是一个顶点着色器。
// 这段 GLSL 代码定义了一个简单的顶点着色器,版本是 330 核心 (core) 版本。
program->addShaderFromSourceCode(QOpenGLShader::Vertex, R"(
#version 330 core // 指定 GLSL 的版本,330 表示 OpenGL 3.3 版本
layout(location = 0) in vec3 vertexPosition; // 声明一个输入变量,位置是 0,类型是三维向量 (vec3)
void main() {
gl_Position = vec4(vertexPosition, 1.0); // 将输入的顶点位置转换为齐次坐标,赋值给内置变量 gl_Position
}
)");
// 添加并编译片段着色器源码。
// QOpenGLShader::Fragment 表示这是一个片段着色器。
// 这段 GLSL 代码定义了一个简单的片段着色器。
program->addShaderFromSourceCode(QOpenGLShader::Fragment, R"(
#version 330 core // 指定 GLSL 的版本,330 表示 OpenGL 3.3 版本
out vec4 fragColor; // 声明一个输出变量,类型是四维向量 (vec4),表示颜色
void main() {
fragColor = vec4(0.0, 1.0, 0.0, 1.0); // 将片段的颜色设置为绿色 (R=0.0, G=1.0, B=0.0, Alpha=1.0)
}
)");
5 VAO,VBO,EBO
在 OpenGL 中,
VAO
(Vertex Array Object)、VBO
(Vertex Buffer Object)、和
EBO
(Element Buffer Object)是管理和组织顶点数据的核心对象。它们在现代 OpenGL
编程中用于高效地传递和绘制几何数据。以下是它们的详细解释:1. VAO (Vertex Array Object) - 顶点数组对象
- 作用:
VAO
是一个容器对象,记录与顶点属性相关的所有状态配置。它存储了顶点属性指针的设置,并与绑定的VBO
和EBO
一起定义了顶点数据的组织方式。- 功能:通过使用
VAO
,你可以一次性设置所有顶点属性配置(例如位置、颜色、法线等),之后只需绑定VAO
即可快速绘制相应的几何体,而无需重新配置这些属性。- 绑定:通过
glBindVertexArray
函数绑定一个VAO
,然后所有后续的顶点属性设置(如glVertexAttribPointer
)都会被记录在这个VAO
中。2. VBO (Vertex Buffer Object) - 顶点缓冲对象
- 作用:
VBO
是一个在显存中存储顶点数据的缓冲区对象。它用于在 GPU 上存储大量的顶点数据(例如顶点坐标、颜色、法线等),以便在渲染时快速访问。- 功能:
VBO
通过glBufferData
或glBufferSubData
函数上传数据,数据可以是顶点坐标、颜色、纹理坐标等。VBO
与VAO
结合使用,决定了如何将这些数据提供给顶点着色器。- 绑定:通过
glBindBuffer(GL_ARRAY_BUFFER, vbo)
绑定VBO
,然后可以使用glVertexAttribPointer
来定义如何解释这些数据。3. EBO (Element Buffer Object) - 元素缓冲对象
- 作用:
EBO
是在显存中存储索引数据的缓冲区对象。它用于保存索引数组,这些索引用于在绘制时引用VBO
中的顶点数据,从而避免顶点数据的重复定义。- 功能:使用
EBO
,可以通过索引重用顶点数据,从而减少顶点数据的冗余和内存使用。索引缓冲区存储的整数引用顶点缓冲区中的顶点数据,在渲染时通过
glDrawElements
函数绘制几何体。- 绑定:通过
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
绑定EBO
,然后可以使用glDrawElements
函数根据索引数组绘制图元。工作流程:
- 创建 VAO:
glGenVertexArrays
和glBindVertexArray
创建并绑定VAO
。- 创建 VBO 并绑定数据:
glGenBuffers
和glBindBuffer(GL_ARRAY_BUFFER)
创建并绑定VBO
,然后通过glBufferData
上传顶点数据。- 设置顶点属性指针:使用
glVertexAttribPointer
设置顶点属性指针(如位置、颜色等),然后启用顶点属性数组。- 创建 EBO 并绑定索引数据:
glGenBuffers
和glBindBuffer(GL_ELEMENT_ARRAY_BUFFER)
创建并绑定EBO
,然后通过
glBufferData
上传索引数据。- 绘制:通过
glDrawElements
使用索引缓冲区绘制图元。总结:
VAO
:管理顶点属性配置,包含顶点数据和索引数据的绑定信息。VBO
:存储顶点数据(如位置、颜色等),提供给顶点着色器使用。EBO
:存储顶点索引数据,定义顶点的绘制顺序,以减少冗余。
这里需要强调一点。
VAO,就像一个记录仪, 会记录当前状态机下发生的”一切“!包括一些 一些对象的绑定和解绑。
比如,VAO会记录EBO的绑定和解绑过程。
所以,如果EBO在VAO之前解绑,就会导致 (glDrawElements)报错!!!!!
但是 VBO在VAO之前解绑,不会导致错误,是为啥?
这是因为,VAO不记录VBO的绑定状态!!!!!(但是会记录EBO的绑定状态!)
至于为啥,这么设计,我不知道:
再回到之前报错的问题:
所以如果你不记录EBO 就必须直接给出 索引:
这样才不会报错
// 定义索引数组,指定顶点的绘制顺序
unsigned int indices[] = {
0, 1, 2, // 第一个三角形
2, 3, 0 // 第二个三角形
};
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &indices);
如果记录了,就不用给:
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);