【OpenGL】Create a triangle 1

Triangle

// 顶点数组对象:Vertex Array Object, VAO // 顶点缓冲对象:Vertex Buffer Object, VBO // 元素缓冲对象:Element Buffer Object EBO

// 着色器:Shader // 顶点数据:Vertex(3D) + RGB // 图元: Primitive

顶点着色器: Vertex Shader → 输入3D,输出2D

片段着色器: 用于计算最终像素的颜色

Alpha测试和混合(Blending):混合的意思就是如果计算出了多个三角形,经过混合之后的像素颜色不同

我要做的:必须至少定义一个顶点着色器片段着色器

标准化设备坐标(-1,1)之间的 normalized device coordinates→ 屏幕空间坐标 Screen-space coordinates

【标准化设备坐标】通过glViewport进行 Viewport Tranfrom转变为【屏幕空间坐标】。

顶点缓冲对象VBO来管理这个内存,会在GPU内存中储存大量顶点:

  • 可以一次性发动一大批数据到显卡上
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*Hello Triangle*/
// 顶点数组对象:Vertex Array Object, VAO
// 顶点缓冲对象:Vertex Buffer Object, VBO
// 元素缓冲对象:Element Buffer Object EBO

// 着色器:Shader
// 顶点数据:Vertex(3D) + RGB
// 图元: Primitive


#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>

// 注册函数 register a function
// 窗口改变 (window) -> 视口改变(viewport) : viewport is waiting for changing from window
// 总结:谁waiting/被动 -> 谁就call_back
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void process_input(GLFWwindow* window);


const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// 着色器语言GLSL(OpenGL Shading Language)
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";

const char *fragmentShader1Source = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n";

const char *fragmentShader2Source = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);\n"
"}\n\0";


int main()
{
// ------------------- 初始化glfw -------------------
glfwInit();
// 初始化版本号 -> 330
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

// ------------------- 初始化window -------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
// 如果没有创建成功
if (window == NULL) {
std::cout << "cant create a window" << std::endl;
glfwTerminate();
return -1;
}
//设置当前渲染上下文,其实就是告诉gl我现在要渲染的是 : window这个current context
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);



// ------------------- 初始化GLAD-------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
// 没有成功初始化GLAD
std::cout << "cant initialize the GLAD" << std::endl;
return -1;
}

// ------------- 顶点着色器 vertex shader ------
int success;
char infoLog[512];
unsigned int vertexShader;
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);
std::cout << "ERROR:SHAER::VERTEXT::COMPILATION_FAILED\n" << std::endl;
}

// ---------- 片段着色器 fragment shader -------
unsigned int fragment1Shader;
fragment1Shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment1Shader, 1, &fragmentShader1Source, NULL);
glCompileShader(fragment1Shader);
glGetShaderiv(fragment1Shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment1Shader, 512, NULL, infoLog);
std::cout << "ERROR::SHAER::FRAGMENT::COMPILATION_FAILED\n" << std::endl;
}

unsigned int fragment2Shader;
fragment2Shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment2Shader, 1, &fragmentShader2Source, NULL);
glCompileShader(fragment2Shader);
glGetShaderiv(fragment2Shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment2Shader, 512, NULL, infoLog);
std::cout << "ERROR::SHAER::FRAGMENT::COMPILATION_FAILED\n"<< std::endl;
}

// ---------------- 链接着色器 ------------------
unsigned int shader1Program, shader2Program;
shader1Program = glCreateProgram();
shader2Program = glCreateProgram();

glAttachShader(shader1Program, vertexShader);
glAttachShader(shader1Program, fragment1Shader);
glLinkProgram(shader1Program);
glGetProgramiv(shader1Program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader1Program, 512, NULL, infoLog);
}

glAttachShader(shader2Program, vertexShader);
glAttachShader(shader2Program, fragment2Shader);
glLinkProgram(shader2Program);
glGetProgramiv(shader2Program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader2Program, 512, NULL, infoLog);
}

// ------------------- 顶点数据 ---------------------
// 定义一些顶点数据
float firstTriangle[] = {
// first triangle
-0.9f, -0.5f, 0.0f, // left
-0.0f, -0.5f, 0.0f, // right
-0.45f, 0.5f, 0.0f, // top
};
float secondTriangle[] = {
0.0f, -0.5f, 0.0f,
0.9f, -0.5f, 0.0f,
0.45f, 0.5f, 0.0f
};
// EBO (Indexed Drawing)
unsigned int indices[] = {
0, 1, 3,
1, 2, 3
};
// ---------------- 定义VAO,VBO对象(gen -> bind -> load)----------------
unsigned int VBOs[2], VAOs[2];
glGenVertexArrays(2, VAOs);
glGenBuffers(2, VBOs);
// glGenBuffers(1, &EBO);

glBindVertexArray(VAOs[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(firstTriangle), firstTriangle, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

glBindVertexArray(VAOs[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);


// 用一个while循环来简单渲染
while (!glfwWindowShouldClose(window)) {
// 处理输入
process_input(window);

// 先设置清除缓存的color
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

// step4. 绘制图像
glUseProgram(shader1Program);
glBindVertexArray(VAOs[0]);
glDrawArrays(GL_TRIANGLES, 0, 3);

glUseProgram(shader2Program);
glBindVertexArray(VAOs[1]);
glDrawArrays(GL_TRIANGLES, 0, 3);

// 颜色缓冲绘图
glfwSwapBuffers(window);
// 监测有没有中断事件
glfwPollEvents();
}
glDeleteVertexArrays(2, VAOs);
glDeleteBuffers(2, VBOs);
glDeleteProgram(shader1Program);
glDeleteProgram(shader2Program);

glfwTerminate();
return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}

void process_input(GLFWwindow* window) {
// 如果用户按了ESC按键,就关闭窗口,如果没按下就会返回GLFW_RELEASE
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
std::cout << "you have press esc" << std::endl;
// !!!不是glfwWindowshouldclose 而是 set_xxx
glfwSetWindowShouldClose(window, true);
}
}
  • 渲染流程
    • 初始化
      • 创建window
      • 初始化window
      • 加载GLAD
    • 创建顶点着色器
      • create
      • source
      • compile
    • 创建片段着色器
      • create
      • source
      • compile
    • 链接着色器
      • attanch
      • link
      • 产生shaderProgram
    • VAO,VBO,EBO定义和加载
      • generate
      • bind
      • load buffer data(加载顶点数据)
    • while循环渲染
      • 处理输入
      • 清缓存
      • 绘制
        • use shaderProgram
        • bind要绘制的VAO
        • draw当前绑定的VAO中的值
    • delete VAO,VBO,shaderProgram...