OpenGL学习之路之三角形绘制

OpenGL学习之路之三角形绘制

十一月 02, 2021

先从几何阶段取出顶点转换成vbo转到vao如果有重复顶点可以转到EBo
openGL是一个状态机只能运行context的状态只能放一个vao
状态机中必须要一个vao

VAO

1
2
3
   unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);//注意

VBO

1
2
3
4
unsigned int VBO;
glGenBuffers(1, &VBO);//一个缓冲ID生成一个VBO对象建立顶点缓冲对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);//新创建的缓冲绑定到GL_ARRAY_BUFFER目标
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//它会把之前定义的顶点数据复制到缓冲的内存中

一定要绑定顶点数组

shader

顶点着色器

1
2
3
4
   unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);//由于我们正在创建一个顶点着色器,传递的参数是GL_VERTEX_SHADER
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);//这个着色器源码附加到着色器对象上
glCompileShader(vertexShader);//编译着色器

片段着色器

1
2
3
4
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);

着色器程序

1
2
3
4
5
6
7
   unsigned int shaderProgram;
shaderProgram = glCreateProgram();//建立着色器程序对象
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);//附加着色器
glLinkProgram(shaderProgram);//连接着色器
glDeleteShader(vertexShader);//着色器对象链接到程序对象以后,记得删除着色器对象,我们不再需要它们了
glDeleteShader(fragmentShader);

序列化数据,可以得到数据的属性,是uv图片还是顶点信息

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

EBO的使用
需要加人索引
unsigned int indices[] = { // 注意索引从0开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};来确定三角形
放发与VBO类似当有点点区别
绑定缓存时GL_ELEMENT_ARRAY_BUFFER,

1
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

绑定缓存数据的是索引值

1
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

在具体绘画过程中

1
2
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);//这是vao没有的

用的函数也是和VAO绘制有区别的
三角形不用EBO的代码

四边形代码如下

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#define GLEW_STATIC
#include<GL/glew.h>
#include<GLFW/glfw3.h>
#include<iostream>

void CheckCompileShaderSuccess(unsigned int vertexShader);//检查着色器是否编译成功
void CheckLinkShaderSuccess(unsigned int shaderProgram);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);

//float vertices[] = {
// -0.5f, -0.5f, 0.0f,
// 0.5f, -0.5f, 0.0f,
// 0.0f, 0.5f, 0.0f
//};
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开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};

const char* vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 aPos;\n"
"void main(){\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}\n";

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";
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);MacOSX系统加上这一句
//以上是初始化Glfw,说明我们要使用的OPENGL版本是3.3,我们同样明确告诉GLFW我们使用的是核心模式(Core-profile)。明确告诉GLFW我们需要使用核心模式意味着我们只能使用OpenGL功能的一个子集。

GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOPENGL", NULL, NULL);//前两个参数代表生成窗口大小
if (window == NULL)
{
std::cout << "GLFW窗口初始化失败" << std::endl;
glfwTerminate();//程序终止函数
return -1;
}
glfwMakeContextCurrent(window);
//GLFW初始化
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
std::cout << "GLEW初始化失败" << std::endl;
return -1;
}
//Glew的初始化
glViewport(0, 0, 800, 600);//渲染窗口大小
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//注册函数

unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
//顶点数据绑定
unsigned int VBO;
glGenBuffers(1, &VBO);//一个缓冲ID生成一个VBO对象建立顶点缓冲对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);//新创建的缓冲绑定到GL_ARRAY_BUFFER目标
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//它会把之前定义的顶点数据复制到缓冲的内存中

unsigned EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);



//顶点着色器



unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);//由于我们正在创建一个顶点着色器,传递的参数是GL_VERTEX_SHADER
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);//这个着色器源码附加到着色器对象上
glCompileShader(vertexShader);//编译着色器
CheckCompileShaderSuccess(vertexShader);

//片段着色器
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);

//着色器程序
unsigned int shaderProgram;
shaderProgram = glCreateProgram();//建立着色器程序对象
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);//附加着色器
glLinkProgram(shaderProgram);//连接着色器
CheckLinkShaderSuccess(shaderProgram);
glDeleteShader(vertexShader);//着色器对象链接到程序对象以后,记得删除着色器对象,我们不再需要它们了
glDeleteShader(fragmentShader);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
while (!glfwWindowShouldClose(window))
{
//输入
processInput(window);

//渲染指令
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//来设置清空屏幕所用的颜色,表示清除板的颜色
glClear(GL_COLOR_BUFFER_BIT);//清除颜色缓冲之后


glUseProgram(shaderProgram);//调用着色器
glBindVertexArray(VAO);
//glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);//这是vao没有的
//检查并调用事件,交换缓冲
glfwSwapBuffers(window);//进行屏幕缓冲
glfwPollEvents();//检查函数有没有触发事件

}
glfwTerminate();

return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window) {
//输入
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
}
void CheckCompileShaderSuccess(unsigned int vertexShader) {
//检查着色器是否编译成功
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
}
void CheckLinkShaderSuccess(unsigned int shaderProgram) {
//检查shaderProgram连接成功
int success;
char infoLog[512];
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::Program::Link_FAILED\n" << infoLog << std::endl;
}
}