#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;
const float triangle[]{
-0.5f, -0.5f, 0.0f, // 左下
0.5f, -0.5f, 0.0f, // 右下
0.0f, 0.5f, 0.0f // 正上
};
int screen_width = 1280;
int screen_height = 720;
int main()
{
//一、初始化
//1.初始化GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//默认是可以改变窗口大小,这里让其不能改变窗口大小
glfwWindowHint(GLFW_RESIZABLE, false);
//2.创建窗口
//第一个null表示是否全屏,第二个null表示是否共享上下文窗口。
auto window = glfwCreateWindow(screen_width, screen_height, "Triangle", nullptr, nullptr);
if (window == nullptr)
{
cout << "Failed to Create OpenGL Context" << endl;
glfwTerminate();
return -1;
}
//将窗口上下文设置为线程上下文
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//OpenGL本身就是一个大的状态机,我们把OpenGL的状态称为OpenGL的上下文。当我们设置后使用当前上下文完成渲染!!!
glfwMakeContextCurrent(window);
//3.初始化GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//4.创建视口
glViewport(0, 0, screen_width, screen_height);
//二、数据处理。
//1.定点数据定义
//2.生成与绑定VAO和VBO
//生成了一个顶点缓冲对象VBO,并且将其绑定到顶点缓冲对象上,使用这个顶点缓冲对象的好处是我们不用将顶点数据一个一个的发送到显卡,
//而是可以借助VBO一次性的发送一大批数据过去。!!!然后使用glBufferData将顶点数据绑定到当前默认的缓冲上!!!
GLuint vertex_buffer_object;
glGenBuffers(1, &vertex_buffer_object);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);
//绑定至当前默认的缓冲,GL_STATIC_DRAW 表示我们的三角形位置数据不会被改变。
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);
//生成VAO并绑定。 !!!绑定之后渲染的时候只需要调用一次VAO就可以了。
GLuint vertex_array_object;
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
//设置顶点属性指针:我们用 glVertexAttribPointer这个函数告诉 OpenGL我们如何解释这些顶点数据
//第一个参数是我们后面会用到的顶点着色器的位置值,3表示的是顶点属性是一个三分量的向量,第三个参数表示的是我们顶点的类型,第四
//个是我们是否希望数据被标准化,就是映射到 0 - 1 之间,第五个参数叫做步长,它表示连续顶点属性之间的间隔,因为我们这里只有顶点
//的位置,所以3个float表示一个顶点的属性。最后一个是数据的偏移量,这里我们的位置属性是在数组的开头,因此这里是 0,并且由于参数
//类型的限制,我们需要将其进行强制类型转换。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
//Enable的函数则是表明我们开启了0的这个通道,默认状态下是关闭的。
glEnableVertexAttribArray(0);
glBindVertexArray(0); //VAO
glBindBuffer(GL_ARRAY_BUFFER, 0); //VBO
//以上步骤通过VAO、VBO将顶点数据储存在显卡的 GPU上了
//三、顶点与片段着色器(用来处理这些存储GPU上的数据)
//流程:对着色器源码进行编译生成着色器。然后将这两个着色器链接到一个着色器程序,这样到时候渲染只需要调用一个着色器程序即可,并且
//可以将编译好的顶点和片段着色器进行删除,直接使用链接好的就行。
//着色器用GLSL来编写,下面为源码
const char *vertex_sharer_source =
"#version 330 core\n" //版本
"layout (location=0) in vec3 aPos;\n" //设置顶点属性的位置值
"void main()\n"
"{\n"
//将之前的顶点数据直接放入GLSL已经定义好的内嵌数据中。相当于顶点着色器的输出
" gl_Position = vec4(aPos,1.0);\n"
"}\n\0";
const char *fragment_shader_source=
"#version 330 core\n"
"out vec4 FragColor;\n" //out输出向量,表示输出颜色
"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_sharer_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);
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);
//利用着色器程序和VAO来绘制三角形
while (!glfwWindowShouldClose(window))
{
//绘制流程:
//清屏
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
//使用着色器程序
glUseProgram(shader_program);
//绑定VAO
glBindVertexArray(vertex_array_object);
//绘制!!
//第一个参数表示我们是要绘制三角形(库自带),第二个参数表示我们顶点数组的起始索引值,第三个参数表示我们要绘制的顶点数量,这里绘制三角形我们要绘制三个顶点。
glDrawArrays(GL_TRIANGLES, 0, 3);
//解除绑定VAO
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
//五、善后
//删除VAO和VBO
glDeleteVertexArrays(1, &vertex_array_object);
glDeleteBuffers(1, &vertex_buffer_object);
glfwTerminate();
return 0;
}
手动绘制三角形