前言
这篇博客主要是记录在学习LearnOpenGL过程中遇到的函数,以及流程问题,越学到后面越感觉混乱,因此做个记录。由于本博客的特殊性,不会有详细说明,如果想了解更多可以阅读LearnOpenGL或者在博客下方评论,也可以私信博主。
此外为了督促,博主决定一周至少更新一小章,如果本文有幸被各位看到,欢迎各位催更!
行文目录
入门篇
创建窗口
用到的函数
初始化GLFW窗口
glfwInit:初始化GLFW,放在最开始
glfwWindowHint:用于配置GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 主版本号为3
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // 次版本号为3
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 表示使用核心模式
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // 用户不可修改窗口大小
- 第一个参数代表选项名称
- 第二个参数接受一个整型,设置这个选项的值
MAC系统需要添加下面的语句:
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
创建窗口对象
glfwCreateWindow:创建窗口对象
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
if (window == nullptr)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
- 第一个参数:窗口的宽
- 第二个参数:窗口的高
- 第三个参数:窗口的名称(标题)
- 第四个参数:博主还没涉及到,暂未nullptr
- 第五个参数:博主还没涉及到,暂未nullptr
- 返回值:GLFWwindow对象的指针
设置上下文
glfwMakeContextCurrent:设置上下文
glfwMakeContextCurrent(window);
- 第一个参数:窗口(GLFWwindow类型)
初始化GLEW
初始化GLEW需要再调用OpenGL函数前
glewInit:初始化GLEW
glewExperimental = GL_TRUE; // 让GLEW用更多现代化技术
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
- 返回值:是否初始化成功
创建视口
glfwGetFramebufferSize:获取窗口的维度保存在第二和三个参数中:
int width, height;
glfwGetFramebufferSize(window, &width, &height);
- 第一个参数:窗口(GLFWwindow类型)
- 第二个参数:存储窗口宽度的变量
- 第三个参数:存储窗口长度的变量
glViewport:设置窗口的维度
glViewport(0, 0, width, height);
- 第一个参数:左下角x的位置
- 第二个参数:左下角y的位置
- 第三个参数:窗口的宽度
- 第四个参数:窗口的高度
游戏循环中
glfwWindowShouldClose :检查一次GLFW是否被要求退出
glfwWindowShouldClose(window)
- 第一个参数:窗口(GLFWwindow类型)
glfwPollEvents:检查有没有触发什么事件(比如键盘输入、鼠标移动等)
glfwPollEvents();
glfwSwapBuffers:交换颜色缓冲
glfwSwapBuffers(window);
- 第一个参数:窗口(GLFWwindow类型)
释放资源
glfwTerminate:清理所有的资源并正确地退出应用程序
glfwTerminate();
创建窗口流程
你好,三角形
用到的函数
生成VBO对象
glGenBuffers:生成一个VBO对象(VAO,EBO代码同)
GLuint VBO;
glGenBuffers(1, &VBO);
- 第一个参数:缓冲ID
- 第二个参数:VBO对象(GLuint型)
glBindBuffer:创建的缓冲绑定到各种缓冲上
glBindBuffer(GL_ARRAY_BUFFER, VBO);
- 第一个参数:缓冲类型,顶点缓冲对象是GL_ARRAY_BUFFER,EBO中是GL_ELEMENT_ARRAY_BUFFER
- 第二个参数:缓冲
glBufferData:把之前定义的顶点数据复制到缓冲内存
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
- 第一个参数:缓冲类型,顶点缓冲对象是GL_ARRAY_BUFFER,EBO中是GL_ELEMENT_ARRAY_BUFFER
- 第二个参数:指定传输数据的大小,字节为单位
- 第三个参数:希望发送的实际数据
- 第四个参数:希望显卡如何管理给定数据
GL_STATIC_DRAW :数据不会或几乎不会改变。
GL_DYNAMIC_DRAW:数据会被改变很多。
GL_STREAM_DRAW :数据每次绘制时都会改变。
编译着色器
glCreateShader:创建着色器对象
GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
- 第一个参数:创建的着色器类型,顶点着色器是GL_VERTEX_SHADER,片段着色器是GL_FRAGMENT_SHADER
glShaderSource:将着色器源码附加到着色器对象上
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
- 第一个参数:要编译的着色器对象
- 第二个参数:传递的源码字符串数量
- 第三个参数:着色器的源码
- 第四个参数:暂未涉猎,先设为NULL
glCompileShader:编译着色器
glCompileShader(vertexShader);
- 第一个参数:要编译的着色器对象
检查编译成功与否
glGetShaderiv:检查是否编译成功
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
- 第一个参数:要编译的着色器对象
- 第二个参数:编译状态,是一个内置量
- 第三个参数:存储是否编译成功,1是成功,0是失败
glGetShaderInfoLog:打印失败信息
if(!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
- 第一个参数:要编译的着色器对象
- 第二个参数:消息的长度
- 第三个参数:暂未涉猎,设置为NULL
- 第四个参数:打印信息的GLchar数组
着色器程序
glCreateProgram:创建着色器程序
GLuint shaderProgram;
shaderProgram = glCreateProgram();
- 返回值:并返回新创建程序对象的ID引用(GLuint型)
glAttachShader:编译的着色器附加到程序对象
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
- 第一个参数:着色器程序对象的ID引用
- 第二个参数:编译后的着色器对象
glLinkProgram:链接着色器程序
glLinkProgram(shaderProgram);
- 第一个参数:着色器程序对象的ID引用
glGetProgramiv、glGetProgramInfoLog:检查编译是否失败并打印失败信息
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
...
}
glUseProgram:激活程序对象
glUseProgram(shaderProgram);
- 第一个参数:着色器程序对象的ID引用
glDeleteShader:删除着色器对象
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
- 第一个参数:着色器程序对象的ID引用
链接顶点属性
glVertexAttribPointer:告诉OpenGL如何解析顶点数据(应用到逐个顶点属性上)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
- 第一个参数:指定我们要配置的顶点属性,在顶点着色器中使用layout(location = 0)定义了position顶点属性的位置值(Location),它可以把顶点属性的位置值设置为0。因为我们希望把数据传递到这一个顶点属性中。说简单点就是第一个参数所在的位置
- 第二个参数:指定顶点属性的大小。顶点属性是一个vec3,它由3个值组成,所以大小是3
- 第三个参数:指定数据的类型,这里是GL_FLOAT(GLSL中vec*都是由浮点数值组成的)
- 第四个参数:定义我们是否希望数据被标准化(Normalize)
- 第五个参数:它告诉我们在连续的顶点属性组之间的间隔
- 第六个参数:最后一个参数的类型是GLvoid*,所以需要我们进行这个奇怪的强制类型转换。它表示位置数据在缓冲中起始位置的偏移量(Offset)。由于位置数据在数组的开头,所以这里是0
glEnableVertexAttribArray:启用顶点属性
glEnableVertexAttribArray(0);
- 第一个参数:顶点属性值
VAO
生成代码同VBO
glBindVertexArray:绑定VAO
glBindVertexArray(VAO);
- 第一个参数:VAO
VAO的绑定与使用
// ..:: 初始化代码(只运行一次 (除非你的物体频繁改变)) :: ..
// 1. 绑定VAO
glBindVertexArray(VAO);
// 2. 把顶点数组复制到缓冲中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
//4. 解绑VAO
glBindVertexArray(0);
[...]
// ..:: 绘制代(游戏循环中) :: ..
// 5. 绘制物体
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
someOpenGLFunctionThatDrawsOurTriangle();
glBindVertexArray(0);
EBO
glDrawElements:EBO中的渲染
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
- 第一个参数:指定了绘制模式
- 第二个参数:打算绘制的顶点个数,矩形是两个三角形共6个顶点
- 第三个参数:索引的类型
- 第四个参数:EBO中偏移量
EAO的绑定与使用
// ..:: 初始化代码 :: ..
// 1. 绑定顶点数组对象
glBindVertexArray(VAO);
// 2. 把我们的顶点数组复制到一个顶点缓冲中,供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. 复制我们的索引数组到一个索引缓冲中,供OpenGL使用,就是多了这里
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 3. 设定顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
// 4. 解绑VAO(不是EBO!)
glBindVertexArray(0);
[...]
// ..:: 绘制代码(游戏循环中) :: ..
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
glBindVertexArray(0);
glPolygonMode:绘制图元的方式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
- 第一个参数:打算将其应用到所有的三角形的正面和背面
- 第二个参数:GL_LINE用线来绘制,GL_FILL填充模式(默认)
着色器
glGetUniformLocation:查询unifrom变量的位置值
GLint vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
- 第一个参数:指定了着色器程序
- 第二个参数:uniform变量名
- 返回值:uniform变量地址,-1表示没有找到
glUniform4f:设置uniform的值。
GLfloat timeValue = glfwGetTime();
GLfloat greenValue = (sin(timeValue) / 2) + 0.5;
GLint vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUseProgram(shaderProgram);
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
- 第一个参数:uniform变量地址
- 第二个参数:变量值的第一个数
- 第三个参数:变量值的第二个数
- 第四个参数:变量值的第三个数
- 第五个参数:变量值的第四个数
注意:在调用glUniform4f更新之前必须使用程序glUseProgram。