当前位置:网站首页>第 4 篇:绘制四边形
第 4 篇:绘制四边形
2022-06-26 03:41:00 【代码骑士】
目录
0、创建项目
(0)选择x64平台
(1)添加链接
打开项目属性
打开项目目录添加文件路径:
包含目录添加:D:\OpenGL_Link\Includes;
库目录添加:D:\OpenGL_Link\Libs;
打开链接器/输入添加:
glfw3.lib;opengl32.lib;
在项目源文件夹下添加glad.c文件
新建main.cpp文件,测试代码,没问题即可。
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
int main() {
//初始化GLFW
glfwInit();//初始化GLFW
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);//MAC OS
glfwWindowHint(GLFW_RESIZABLE, false);//关闭可调节窗口大小
std::cout << "hello world!" << std::endl;
return 0;
}
输出结果
1、初始化
包括:初始化GLFW、创建窗口、初始化GLAD、创建视口
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
//设置屏幕宽、高
const int screen_width = 800;
const int screen_height = 600;
int main() {
//初始化GLFW
glfwInit();//初始化GLFW
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);//MAC OS
glfwWindowHint(GLFW_RESIZABLE, false);//关闭可调节窗口大小
//创建窗口
auto window = glfwCreateWindow(screen_width, screen_height, "Quad", nullptr, nullptr);
if (window == nullptr) {
std::cout << "Failed to Create OpenGL Context" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//将窗口的上下文设置为当前线程的上下文(上下文:指当前状态机的状态)
//初始化GLAD,加载OpenGL的函数指针地址的函数
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//创建视口
glViewport(0, 0, screen_width, screen_height);
return 0;
}
2、顶点输入
//四边形的顶点数据
float vertices[] = {
//第一个三角形
0.5f,0.5f,0.0f,//right up
0.5f,-0.5f,0.0f,//right down
-0.5f,-0.5f,0.0f,//left down
//第二个三角形
-0.5f,-0.5f,0.0f,//left down
0.5f,0.5f,0.0f,//right up
-0.5f,0.5f,0.0f,//left up
};
3、数据处理
(1)VBO
我们有了顶点数据,接下来就是将这些顶点数据发送到GPU中去处理,这里我们要生成一个顶点缓冲对象VBO,并将顶点数据绑定在VBO上,通过这个顶点缓冲对象我们就可以将一大批顶点数据一次性的发送到显卡上面,然后使用glfwBufferData将顶点数据绑定到当前的默认缓冲上,这里的GL_STATIC_DRAW表示我们的四边形位置数据不会改变。
//生成并绑定VBO
GLuint vertex_buffer_object;
glGenBuffers(1, &vertex_buffer_object);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);
//将顶点的数据绑定到当前的默认缓冲中
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
(2)VAO
这里我们还需要生成一个顶点数组对象VAO,使用VAO原因是:首先我们使用的核心模式要求我们实用VAO,其次是使用VAO的好处在于我们在渲染的时候只需要调用一次VAO就可以了,之前的数据都对应存储在了VAO中,不用在调用VBO了。也就是说VAO的生成过程也跟VBO一样,需要先生成再绑定,等到这些操作都进行完,我们就可以解绑我们的VAO、VBO了。
//生成并绑定VAO
GLuint vertex_array_object;
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
(3)顶点属性
发送到GPU之后我们还要告诉OpenGL我们如何解释这些顶点数据。因此我们用glVertexAttribPointer这个函数告诉OpenGL我们如何解释这些顶点数据。
//设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer函数说明:
第一个参数:0是我们后面会使用到的顶点着色器的位置值,
第二个参数:3表示的是顶点属性是一个三分量的向量,
第三个参数:GL_FLOAT表示的是我们顶点的类型,
第四个参数:GL_FALSE表示我们是否希望数据被标准化,
第五个参数:3*sizeof(float) 叫做步长,它表示连续顶点属性之间的间隔,因为我们这里只有顶点的位置,所以我们将步长设置为这个,表示下组数据在3个float之后。
最后一个参数:(void*)0 是数据的偏移量,这里我们的位置属性是在数组的开头,因此这里是0,并且由于参数类型的限制,我们需要将其进行强制类型转换。
而下面Enable的函数则是表明我们开启了0的这个通道,默认状态下是关闭的,因此我们要在此开启一下。
(4)解绑VAO和VBO
//解绑VAO和VBO
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
为什么要在这里解绑呢?
原因1:防止之后再继续绑定VAO的时候影响当前的VAO。
原因2:为了使代码更加灵活规范,在渲染需要的时候我们会再绑定VAO。
4、顶点着色器和片段着色器
(1)生成着色器
我们已经通过VAO和VBO将顶点数据存储在显卡的GPU上了,接下来我们会创建顶点和片段着色器真正处理这些数据。这里我们会给出着色器的源码,然后生成并编译着色器,最后将顶点和片段链接到一个着色器程序,在之后的渲染流程中我们会使用这个着色器程序,最后将之前的着色器删除。
接下来我们给出顶点着色器和片段着色器的源码,都是用GLSL语言编写的。
// 顶点着色器源码
const char* vertex_shader_source =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n" // 位置变量的属性位置值为0
"void main()\n"
"{\n"
" gl_Position = vec4(aPos, 1.0);\n"
"}\n\0";
GLSL代码分析:
第一行:表示我们使用的是OpenGL3.3的核心模式。
第二行:就是我们之前说的位置值。
第三行:是创建的main函数
main函数里的代码语句意思是:将我们之前定义好的顶点数据直接输出到GLSL已经定义好的一个内建变量gl_Position中,这个就是我们顶点着色器的输出。也就是说我们在顶点着色器中只是将顶点位置作为顶点着色器进行输出,其他什么也没做。
//片段着色器源码
const char* fragment_shader_source =
"#version 330 core\n"
"out vec4 FragColor;\n" // 输出的颜色向量
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
(2)编译着色器
对之前写好的源码进行编译。
//编译顶点着色器
int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
int success;
char info_log[512];
// 检查着色器是否成功编译,如果编译失败,打印错误信息
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << std::endl;
}
//编译片段着色器
int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// 检查着色器是否成功编译,如果编译失败,打印错误信息
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << std::endl;
}
(3)链接着色器
将顶点和片段2着色器链接到一个着色器程序中,这样我们在渲染时只需要调用一个着色器程序就可以了。
// 链接顶点和片段着色器至一个着色器程序
int shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
// 检查着色器是否成功链接,如果链接失败,打印错误信息
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader_program, 512, NULL, info_log);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << std::endl;
}
(4)删除着色器
因为后面渲染的时候我们只需要用那个我们之前链接好的着色器程序就可以了,不需要再使用顶点和片段着色器了。
// 删除着色器
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
(5)线框模式
//线框模式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
5、渲染
// 渲染循环
while (!glfwWindowShouldClose(window)) {
// 清空颜色缓冲
glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 使用着色器程序
glUseProgram(shader_program);
// 绘制四边形
glBindVertexArray(vertex_array_object); // 绑定VAO
// 绘制四边形
glDrawArrays(GL_TRIANGLES, 0, 6);
// 用EBO绘制四边形
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0); // 解除绑定
// 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
glfwSwapBuffers(window);
glfwPollEvents();
}
6、善后工作
删除之前创建的VAO、VBO,以及调用GLFW的函数清理所有资源并退出。
// 删除VAO/VBO
glDeleteVertexArrays(1, &vertex_array_object);
glDeleteBuffers(1, &vertex_buffer_object);
// 清理所有的资源并正确退出程序
glfwTerminate();
7、完整代码
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
//设置屏幕宽、高
const int screen_width = 800;
const int screen_height = 600;
//四边形的顶点数据
float vertices[] = {
//第一个三角形
0.5f,0.5f,0.0f,//right up
0.5f,-0.5f,0.0f,//right down
-0.5f,-0.5f,0.0f,//left down
//第二个三角形
-0.5f,-0.5f,0.0f,//left down
0.5f,0.5f,0.0f,//right up
-0.5f,0.5f,0.0f,//left up
};
int main() {
//初始化GLFW
glfwInit();//初始化GLFW
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);//MAC OS
glfwWindowHint(GLFW_RESIZABLE, false);//关闭可调节窗口大小
//创建窗口
auto window = glfwCreateWindow(screen_width, screen_height, "Quad", nullptr, nullptr);
if (window == nullptr) {
std::cout << "Failed to Create OpenGL Context" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//将窗口的上下文设置为当前线程的上下文(上下文:指当前状态机的状态)
//初始化GLAD,加载OpenGL的函数指针地址的函数
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//创建视口
glViewport(0, 0, screen_width, screen_height);
//生成并绑定VBO
GLuint vertex_buffer_object;
glGenBuffers(1, &vertex_buffer_object);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);
//将顶点的数据绑定到当前的默认缓冲中
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//生成并绑定VAO
GLuint vertex_array_object;
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
//设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//解绑VAO和VBO
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// 顶点着色器源码
const char* vertex_shader_source =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n" // 位置变量的属性位置值为0
"void main()\n"
"{\n"
" gl_Position = vec4(aPos, 1.0);\n"
"}\n\0";
//片段着色器源码
const char* fragment_shader_source =
"#version 330 core\n"
"out vec4 FragColor;\n" // 输出的颜色向量
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
//编译顶点着色器
int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
int success;
char info_log[512];
// 检查着色器是否成功编译,如果编译失败,打印错误信息
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << std::endl;
}
//编译片段着色器
int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// 检查着色器是否成功编译,如果编译失败,打印错误信息
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << std::endl;
}
// 链接顶点和片段着色器至一个着色器程序
int shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
// 检查着色器是否成功链接,如果链接失败,打印错误信息
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader_program, 512, NULL, info_log);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << std::endl;
}
// 删除着色器
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
//线框模式
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// 渲染循环
while (!glfwWindowShouldClose(window)) {
// 清空颜色缓冲
glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 使用着色器程序
glUseProgram(shader_program);
// 绘制四边形
glBindVertexArray(vertex_array_object); // 绑定VAO
// 绘制四边形
glDrawArrays(GL_TRIANGLES, 0, 6);
// 用EBO绘制四边形
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0); // 解除绑定
// 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
glfwSwapBuffers(window);
glfwPollEvents();
}
// 删除VAO/VBO
glDeleteVertexArrays(1, &vertex_array_object);
glDeleteBuffers(1, &vertex_buffer_object);
// 清理所有的资源并正确退出程序
glfwTerminate();
return 0;
}
输出结果:
8、梳理流程
首先初始化OpenGL,包括四个步骤
然后进行数据处理通过VAO、VBO将其发送到GPU
并设置属性指针告诉GPU如何解释这些数据
然后在着色器中通过顶点和片段着色器进行数据处理
最后进行渲染生成最终图形。
9、EBO
我们的四边形是通过两个三角形拼凑的,从顶点数据中会发现左上和右下的顶点重复了两次,如果进行大规模计算,无疑这种方式会造成大量计算机的资源浪费。想要解决这个问题,其实我们只需存储四边形的四个顶点就好了。EBO可以帮助我们实现这个功能。
创建索引
//四边形的顶点数据
float vertices[] = {
//第一个三角形
0.5f,0.5f,0.0f,//right up
0.5f,-0.5f,0.0f,//right down
-0.5f,-0.5f,0.0f,//left down
//第二个三角形
-0.5f,-0.5f,0.0f,//left down
0.5f,0.5f,0.0f,//right up
-0.5f,0.5f,0.0f,//left up
};
// 索引数据(注意这里是从0开始的)
unsigned int indices[] = {
0, 1, 5, // 第一个三角形
1, 2, 5 // 第二个三角形
};
创建缓冲对象EBO
//生成并绑定EBO
GLuint element_buffer_object; // == EBO
glGenBuffers(1, &element_buffer_object);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_object);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
完整代码
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
//设置屏幕宽、高
const int screen_width = 800;
const int screen_height = 600;
//四边形的顶点数据
float vertices[] = {
//第一个三角形
0.5f,0.5f,0.0f,//right up
0.5f,-0.5f,0.0f,//right down
-0.5f,-0.5f,0.0f,//left down
//第二个三角形
-0.5f,-0.5f,0.0f,//left down
0.5f,0.5f,0.0f,//right up
-0.5f,0.5f,0.0f,//left up
};
// 索引数据(注意这里是从0开始的)
unsigned int indices[] = {
0, 1, 5, // 第一个三角形
1, 2, 5 // 第二个三角形
};
int main() {
//初始化GLFW
glfwInit();//初始化GLFW
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);//MAC OS
glfwWindowHint(GLFW_RESIZABLE, false);//关闭可调节窗口大小
//创建窗口
auto window = glfwCreateWindow(screen_width, screen_height, "Quad", nullptr, nullptr);
if (window == nullptr) {
std::cout << "Failed to Create OpenGL Context" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//将窗口的上下文设置为当前线程的上下文(上下文:指当前状态机的状态)
//初始化GLAD,加载OpenGL的函数指针地址的函数
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//创建视口
glViewport(0, 0, screen_width, screen_height);
//生成并绑定VBO
GLuint vertex_buffer_object;
glGenBuffers(1, &vertex_buffer_object);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);
//将顶点的数据绑定到当前的默认缓冲中
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//生成并绑定VAO
GLuint vertex_array_object;
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
//生成并绑定EBO
GLuint element_buffer_object; // == EBO
glGenBuffers(1, &element_buffer_object);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_object);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//解绑VAO和VBO
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// 顶点着色器源码
const char* vertex_shader_source =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n" // 位置变量的属性位置值为0
"void main()\n"
"{\n"
" gl_Position = vec4(aPos, 1.0);\n"
"}\n\0";
//片段着色器源码
const char* fragment_shader_source =
"#version 330 core\n"
"out vec4 FragColor;\n" // 输出的颜色向量
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
//编译顶点着色器
int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
int success;
char info_log[512];
// 检查着色器是否成功编译,如果编译失败,打印错误信息
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << std::endl;
}
//编译片段着色器
int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// 检查着色器是否成功编译,如果编译失败,打印错误信息
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << std::endl;
}
// 链接顶点和片段着色器至一个着色器程序
int shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
// 检查着色器是否成功链接,如果链接失败,打印错误信息
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader_program, 512, NULL, info_log);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << std::endl;
}
// 删除着色器
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
//线框模式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// 渲染循环
while (!glfwWindowShouldClose(window)) {
// 清空颜色缓冲
glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 使用着色器程序
glUseProgram(shader_program);
// 绘制四边形
glBindVertexArray(vertex_array_object); // 绑定VAO
// 绘制四边形
glDrawArrays(GL_TRIANGLES, 0, 6);
// 用EBO绘制四边形
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0); // 解除绑定
// 交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动等)
glfwSwapBuffers(window);
glfwPollEvents();
}
// 删除VAO/VBO
glDeleteVertexArrays(1, &vertex_array_object);
glDeleteBuffers(1, &vertex_buffer_object);
// 清理所有的资源并正确退出程序
glfwTerminate();
return 0;
}
输出结果:同上。
边栏推荐
- Camera-memory内存泄漏分析(三)
- 2020 summary: industrial software development under Internet thinking
- 2022.6.24-----leetcode.515
- "Renegotiation" agreement
- Prism framework project application - Navigation
- Is the waiting insurance record a waiting insurance evaluation? What is the relationship between the two?
- TiFlash 函数下推必知必会丨十分钟成为 TiFlash Contributor
- After Ali failed to start his job in the interview, he was roast by the interviewer in the circle of friends (plug)
- MySQL高級篇第一章(linux下安裝MySQL)【下】
- Restful API interface design standards and specifications
猜你喜欢
Uni app custom selection date 1 (September 16, 2021)
Nepal graph learning Chapter 3_ Multithreading completes 6000w+ relational data migration
The kotlin project is running normally and the R file cannot be found
开源!ViTAE模型再刷世界第一:COCO人体姿态估计新模型取得最高精度81.1AP
【MySQL】 MySQL 导出数据库
Redux thunk simple case, advantages, disadvantages and thinking
“再谈”协议
Upload file / text / picture, box shadow
ABP framework Practice Series (II) - Introduction to domain layer
Partition, column, list
随机推荐
Uni app, the text implementation expands and retracts the full text
优化——多目标规划
Multimedia elements, audio, video
Uni app custom navigation bar component
js实现文字跑马灯效果
Dynamic segment tree leetcode seven hundred and fifteen
Procédures stockées MySQL
Class diagram
2022.6.25-----leetcode.剑指offer.091
EF core Basics
MySQL addition, deletion, query and modification (primary level)
2022.6.23-----leetcode.30
【MySQL】 MySQL 导出数据库
Navicat16 wireless trial
Camera-memory内存泄漏分析(二)
Prism framework project application - Navigation
MySQL高级部分( 四: 锁机制、SQL优化 )
(15)Blender源码分析之闪屏窗口显示菜单功能
An error occurred using the connection to database 'on server' 10.28.253.2‘
Communication mode between processes