【OpenGL 学习笔记】第 4 篇:绘制四边形
目录
0、创建项目
1、初始化
2、顶点输入
3、数据处理
(1)VBO
(2)VAO
(3)顶点属性
(4)解绑VAO和VBO
4、顶点着色器和片段着色器
(1)生成着色器
(2)编译着色器
(3)链接着色器
(4)删除着色器
(5)线框模式
5、渲染
6、善后工作
7、完整代码
8、梳理流程
9、EBO
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() {//初始化GLFWglfwInit();//初始化GLFWglfwWindowHint(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 OSglfwWindowHint(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() {//初始化GLFWglfwInit();//初始化GLFWglfwWindowHint(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 OSglfwWindowHint(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 up0.5f,-0.5f,0.0f,//right down-0.5f,-0.5f,0.0f,//left down//第二个三角形-0.5f,-0.5f,0.0f,//left down0.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表示我们的四边形位置数据不会改变。
//生成并绑定VBOGLuint 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了。
//生成并绑定VAOGLuint 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和VBOglBindVertexArray(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/VBOglDeleteVertexArrays(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 up0.5f,-0.5f,0.0f,//right down-0.5f,-0.5f,0.0f,//left down//第二个三角形-0.5f,-0.5f,0.0f,//left down0.5f,0.5f,0.0f,//right up-0.5f,0.5f,0.0f,//left up
};int main() {//初始化GLFWglfwInit();//初始化GLFWglfwWindowHint(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 OSglfwWindowHint(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);//生成并绑定VBOGLuint 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);//生成并绑定VAOGLuint 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和VBOglBindVertexArray(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/VBOglDeleteVertexArrays(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 up0.5f,-0.5f,0.0f,//right down-0.5f,-0.5f,0.0f,//left down//第二个三角形-0.5f,-0.5f,0.0f,//left down0.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
//生成并绑定EBOGLuint element_buffer_object; // == EBOglGenBuffers(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 up0.5f,-0.5f,0.0f,//right down-0.5f,-0.5f,0.0f,//left down//第二个三角形-0.5f,-0.5f,0.0f,//left down0.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() {//初始化GLFWglfwInit();//初始化GLFWglfwWindowHint(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 OSglfwWindowHint(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);//生成并绑定VBOGLuint 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);//生成并绑定VAOGLuint vertex_array_object;glGenVertexArrays(1, &vertex_array_object);glBindVertexArray(vertex_array_object);//生成并绑定EBOGLuint element_buffer_object; // == EBOglGenBuffers(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和VBOglBindVertexArray(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/VBOglDeleteVertexArrays(1, &vertex_array_object);glDeleteBuffers(1, &vertex_buffer_object);// 清理所有的资源并正确退出程序glfwTerminate();return 0;
}
输出结果:同上。
【OpenGL 学习笔记】第 4 篇:绘制四边形相关推荐
- OpenGL学习笔记(一)绘制点线面及多面体
OpenGL学习笔记(一)绘制点线面及多面体 绘制点线面 #include <iostream> #include <GL/GLUT.h> #define PI 3.14159 ...
- openGL学习笔记三十七:绘制简单地图
地形本质上由一个个顶点(x,y,z)组成多个三角面连接而成. 地形有两种来源: 1.美术使用3dmax.maya.bleader工具,画点.线.面,导出三维模型,然后在游戏中加载进来,进行绘制 ...
- OpenGL学习笔记(八):进一步理解VAO、VBO和SHADER,并使用VAO、VBO和SHADER绘制一个三角形
原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7888 ...
- OpenGL学习笔记(一):环境搭建、三维空间坐标系理解以及OpenGL的基本使用
原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7866 ...
- 【OpenGL学习笔记⑧】——键盘控制正方体+光源【冯氏光照模型 光照原理 环境光照+漫反射光照+镜面光照】
✅ 重点参考了 LearnOpenGL CN 的内容,但大部分知识内容,小编已作改写,以方便读者理解. 文章目录 零. 成果预览图 一. 光照原理与投光物的配置 1.1 光照原理 1.2 投光物 二. ...
- 【OpenGL学习笔记⑥】——3D变换【旋转的正方体 实现地月系统 旋转+平移+缩放】
✈️ 文章目录 零. 成果预览图 一.3D立方体的顶点数组 二.纹理旋转 三.纹理缩放 四.画n个3D图形 五.轨道的数学公式 六.深度缓冲(Z 缓冲) 七.完整代码 八.参考附录: 神器的正方体 ☁ ...
- OpenGL学习笔记(十三):将纹理贴图应用到四边形上,对VAO/VBO/EBO/纹理/着色器的使用方式进行总结
原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7919 ...
- OpenGL 学习笔记 II:初始化 API,第一个黑窗,游戏循环和帧率,OpenGL 默认垂直同步,glfw 帧率
前情提要: 上一篇: OpenGL 学习笔记 I:OpenGL glew glad glfw glut 的关系,OpenGL 状态机,现代操作系统的窗口管理器,OpenGL 窗口和上下文 OpenGL ...
- RCNN学习笔记——第三篇: 实现FRCNN网络训练、评价与预测(附全部源码)
RCNN学习笔记--第三篇: 实现FRCNN网络训练.评价与预测(附全部源码) 本文是个人根据B站大佬Bubbliiiing的FRCNN系列视频同步完成FRCNN训练,记录心得和遇见的问题. 关于RC ...
- OracleDesigner学习笔记1――安装篇
OracleDesigner学习笔记1――安装篇 QQ:King MSN:qiutianwh@msn.com Email:qqking@gmail.com 一. 前言 Oracle是当 ...
最新文章
- 【青少年编程】【四级】奇偶之和
- php模板引擎哪个好,php模板引擎原理是什么?
- 为啥不上SOA?中国企业的四大投资顾虑
- 学习笔记Hive(六) —— Hive开发应用
- 深入浅出下一代互联网基础IPFS
- 2018.11.05 NOIP模拟 规避(最短路计数)
- 控制元素的div属性
- 个人收集 - 1、自动消失的消息提示(Js+Div实现)
- windows API 串口编程参考
- linux 查tls模块,TLSSLed · Kali Linux Tools Documents · 看云
- Ansi,UTF8,Unicode编码
- c语言学习指南app,c语言学习手册app
- 人工智能本科专业高校名单大全(440所)
- 大白菜超级U盘启动盘制作工具极速装机版
- 三位数除以两位数竖式计算没有余数_三位数除两位数计算题-云簿杜同学
- 小型双轮差速底盘实现触须避障
- java 双列集合Map 万字详解
- uCOS-II 基础入门教程(九)
- 网页中用快播qvod打开bt种子 在线播放
- Linux —— OpenCv编译安装
热门文章
- 华为麒麟9000性能提升幅度大,但恐难成安卓一哥
- Android手机拍照功能实现
- Excel之用Sumifs完成多条件多列的求和
- 奋斗(2)第12集剧情介绍
- 计算机基础与应用说课ppt课件,广东省“XX杯”说课大赛计算机应用基础类一等奖作品:PPT写字动画的制作现场说课课件.ppt...
- 十进制转换成二进制java
- 第三方软件测试z5x电池,vivo Z5x第三方续航测试结果公布,刷新手机业续航排行榜...
- USB OVER Network的使用(共享usb端口)
- Intel和AMD的区别
- pip install时报错超时(pip._vendor.requests.packages.urllib3.exceptions.ReadTimeoutError: HTTPSConnec)解决方案