初始化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, GL_FALSE);
定义一个窗口唯一标识符,用来存储和被引用(相当于一个身份证信息)
GLFWwindow* window = glfwCreateWindow(800, 600, "i'm a lovely girl", nullptr, nullptr);
第一个参数:宽度。第二个参数:高度。三:名称。四:默认监视器(主显示屏)。五(是否和其它窗口共享上下文)
创建失败就终止。
if (window == nullptr) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
上下文是一个对象,它具有一下信息
渲染状态: 上下文中包含了当前的渲染状态,比如当前使用的顶点缓冲区、顶点数组对象、着色器程序、纹理单元等。这些状态会影响 OpenGL 渲染的结果。
视口信息: 视口是屏幕上用于显示图形的区域,上下文中包含了当前的视口设置,包括位置和大小。
着色器状态: 上下文中包含了当前的顶点着色器和片段着色器程序。这些程序定义了 GPU 如何处理图形数据。
缓冲区状态: 上下文中包含了与渲染相关的缓冲区,比如颜色缓冲区、深度缓冲区、模板缓冲区等。
纹理状态: 包括当前绑定的纹理对象、纹理过滤器、纹理包裹方式等设置。
帧缓冲状态: 上下文中包含了当前绑定的帧缓冲对象,它用于渲染到纹理或多重采样缓冲区。
渲染状态: 包括渲染模式(如线框模式或填充模式)、剔除面的设置等。
OpenGL 版本信息: 上下文中包含了当前 OpenGL 实现的版本号、支持的扩展等信息。
现在的窗口并不具有上下文,只是一个空窗口,我们要将它与上下文联系起来
glfwMakeContextCurrent(window);
下面这个设置就完了,相当于开了一些新功能
glewExperimental = GL_TRUE;
初始化glew
if (glewInit() != GLEW_OK){
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
到目前为止,我们把该初始化的两个库,该设置的版本信息,该创建的窗口都做了,并把窗口和上下文对象连接了起来(牵了根线)。
下面设置帧缓冲区对象(要渲染的区域大小)的大小和窗口大小(渲染的区域在窗口的大小)
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
一般是一样的,可以理解为渲染的作用范围
在主函数之前,我们要写一个顶点着色器和片段着色器源码
//顶点着色器源码
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}\0";
//片段着色器源码
const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"void main()\n"
"{\n"
"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
layout (location = 0) in vec3 position意思是输入一个三维坐标
out vec4 color意思是输出一个四维的颜色
#version 330 core定义版本号
下面创建顶点着色器
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
//将着色器源码附在着色器上
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
//将字符串类型的源码编译
glCompileShader(vertexShader);
glCreatShader(类型)
检查是否创建成功
GLint success;
GLchar 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;
}
创建一个片段着色器,并检查是否出错
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Check for compile time errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
创建着色器程序,连接并链接
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
//删除着色器对象
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glLinkProgram 会对指定的着色器程序进行链接操作,检查各个着色器之间的兼容性,并生成最终的可执行程序,用于在 GPU 上执行渲染操作。
下面输入顶点
GLfloat vertices[] = {
-0.5f,-0.5f,0.0f,
0.5f,-0.5f,0.0f,
0.0f, 0.5f,0.0f
};
创建锅
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
绑定锅(名字和锅具绑定到一起)
// 绑定VAO
glBindVertexArray(VAO);
// 绑定VBO,并将顶点数据复制到VBO中
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData相当于数据线,用于传输数据的。
VAO就像一个餐桌,而VBO是各种盘子
下面配置顶点属性
位置(position=0),每个顶点坐标分量个数(3),类型,是否映射到[0,1](否,我们要[-1,1],步长下一个点的位置,这个不用管偏移量为0但是要强转)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
确保数据有效,从position=0开始
glEnableVertexAttribArray(0);
下面还有一个解绑操作,数据已经传输过去了,现在断开连接(断开VAO和VBO)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
下面是游戏循环
while (!glfwWindowShouldClose(window)) {
//检查事件
glfwPollEvents();
//这一部分是渲染(背景颜色)
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//启用着色器
glUseProgram(shaderProgram);
//VAO里存储了顶点的状态,我们每次渲染都需要绑定一次之前设置好的VAO
glBindVertexArray(VAO);
//画出三角形
glDrawArrays(GL_TRIANGLES, 0, 3);
//解绑,避免被更改
glBindVertexArray(0);
//交换前后缓冲
glfwSwapBuffers(window);
}
//终止程序
glfwTerminate();
一个普通的橙色三角形