1.窗口

创建GLFW窗口对象

GLFWwindow* window = glfwCreateWindow(800, 600, "opengl",NULL,NULL);

  • 800:width
  • 600:height
  • “opengl”:title

初始化GLEW

1
2
3
4
5
6
7
glewExperimental = true;//设置 GLEW 的实验性模式
if (glewInit() != GLEW_OK)
{
printf("Init GLEW failed");
glfwTerminate();
return -1;
}

窗口渲染框架:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#define GLEW_STATIC
#include<GL/glew.h>
#include<GLFW/glfw3.h>
#include<cstdio>
#include<iostream>
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)//GLFW_KEY_ESCAPE:表示esc键,glfwGetKey:获取窗口中键的状态
{
glfwSetWindowShouldClose(window, true);
}
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//创建GLFW窗口对象
GLFWwindow* window = glfwCreateWindow(800, 600, "opengl",NULL,NULL);
glfwMakeContextCurrent(window);//将当前需要渲染的窗口设置为window
//初始化GLEW
glewExperimental = true;//设置 GLEW 的实验性模式
if (glewInit() != GLEW_OK)
{
printf("Init GLEW failed");
glfwTerminate();
return -1;
}

glViewport(0, 0, 800, 600);
while (!glfwWindowShouldClose(window))//判断窗口是否被关闭,未关闭则一直循环
{
processInput(window);
glClearColor(0.5f, 0.2f, 0.3f, 1.0f);//定义一种颜色(rgba四通道),每个通道取值为0~1.
glClear(GL_COLOR_BUFFER_BIT);
//GL_COLOR_BUFFER_BIT:颜色缓冲,glClear:将颜色缓冲填充成glClearColor设置的颜色
glfwSwapBuffers(window);//交换双缓冲,渲染先在后台缓冲区进行,之后再与前台缓冲区交换
//使用双缓冲是为了避免用户看到不完整的、中间过程的渲染结果
glfwPollEvents();//检查有没有触发什么事件(比如键盘输入、鼠标移动等)
}
glfwTerminate();//释放 GLFW 库分配的资源和清理 GLFW 环境
return 0;
}

2.三角形

图形渲染管线:

image-20231215095323007

2.1 定义并绑定VAO

VAO(Vertex Array Object):**保存了一系列的VBO配置和顶点属性指针,它负责告诉GPU,VBO中的信息到底该以几个为一组,对VBO起到解释的作用。

注:一个VAO可以对应多个VBO

image-20231215093925600

1
2
3
unsigned int VAO;//也可以是unsigned int VAO[n],n为VAO的个数
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

2.2 定义并绑定VBO

VBO(Vertex Buffer Object):用于存储实际的顶点数据,可以包含顶点坐标、法线、颜色等信息。

1
2
3
4
5
6
unsigned int VBO;
glGenBuffers(1, &VBO);
//绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//数据传输到缓冲区,GL_STATIC_DRAW:静态绘制,顶点数据不会被修改
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

2.3 创建顶点着色器

顶点着色器:对每个输入顶点的坐标进行计算和变换

1
2
3
4
5
6
7
//vertexShaderSource
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
1
2
3
4
5
6
//创建顶点着色器对象
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
//设置顶点着色器源代码并编译
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);

2.4 创建片段着色器

片段着色器:用于对每个屏幕上的像素(片段)进行处理,决定最终的颜色。

1
2
3
4
5
6
//fragmentShaderSource
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"void main(){\n"
"FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);}\n ";
1
2
3
4
5
6
//创建片段着色器对象
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//设置源代码并编译
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);

2.5 创建着色器程序

1
2
3
4
5
6
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
//将附加到着色器程序的各个着色器连接在一起,以形成一个完整的着色器程序。
glLinkProgram(shaderProgram);

2.6 配置顶点属性指针

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 \* sizeof(float), (void\*)0);

  • 0: 指定顶点着色器中的顶点属性位置(location)。在顶点着色器代码中,使用 layout(location = 0) 来定义的。
  • 3: 指定每个顶点属性包含的分量数量,这里是3,表示三维坐标x、y、z。
  • GL_FLOAT: 指定顶点属性的数据类型,这里是浮点数。
  • GL_FALSE: 指定是否要归一化数据,对于浮点数数据,通常设置为GL_FALSE。
  • 3 * sizeof(float): 指定相邻顶点属性之间的偏移量(以字节为单位)。这里表示每个顶点的大小为3个浮点数,所以偏移量为3 * sizeof(float)。
  • (void*)0: void*无类型指针,指定第一个顶点属性在缓冲区中的偏移量。这里表示从缓冲区的开头开始使用。

glEnableVertexAttribArray(0);:启用顶点属性数组,OpenGL会按照之前配置的顶点属性指针从缓冲区中读取数据。

1
2
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

2.7 绘制三角形

glDrawArrays(GL_TRIANGLES, 0, 3);:

  • GL_TRIANGLES 表示渲染的图元类型,这里是三角形。
  • 0 是起始顶点的索引,表示从顶点数组的第一个顶点开始渲染。
  • 3 是顶点的数量,表示渲染三个顶点。
1
2
3
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);

2.8 绘制多边形

注意:opengl的绘制顺序是逆时针(右手系),当启用背面剔除时,背面将不可见。

1
2
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);

EBO(索引缓冲对象):用于优化和节省内存

1
2
3
4
unsigned int indices[] = {
0, 1, 2, // 第一个三角形
2, 1, 3 // 第二个三角形
};
1
2
3
4
5
//定义并绑定EBO
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

绘制:

1
2
3
4
5
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
/*glDrawArrays(GL_TRIANGLES, 0,3);*/
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

2.9 线框模式

启用线框模式:

1
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

取消线框模式:

1
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);