OpenGL学习之各种流程及函数详解——基于LearnOpenGL(持续更新)

前言

   这篇博客主要是记录在学习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

猜你喜欢

转载自blog.csdn.net/qq_43419761/article/details/129697215
今日推荐