在执行渲染之前,需要将各种顶点相关的数据传递到顶点着色器中,如位置、法线、UV等

顶点数据传递流程

  flowchart TB
    subgraph EBO["EBO"]
        e1["glGenBuffers"] --> e2["glBindBuffer"] --> e3["glBufferData"] --> e4["glBindBuffer(TARGET, 0)"]
    end
    subgraph VBO["VBO"]
        b1["glGenBuffers"] --> b2["glBindBuffer"] --> b3["glBufferData"]
        b4["glBindBuffer(TARGET, 0)"]
    end
    subgraph VAO["VAO"]
        a1["glGenVertexArrays"] --> a2["glBindVertexArray"] --> a3["glVertexAttribPointer"] --- a4["glEnableVertexAttribArray"] --> a5["glBindVertexArray(0)"]
    end
    subgraph delete["Delete"]
        d1["glDeleteVertexArrays"]
        d2["glDeleteBuffers"]
    end
    b3 --> a3
    a5 --> b4 --> d2
    e4 --> d2
    a5 --> d1

    style a5 stroke-width:2px,stroke-dasharray: 2
    style b4 stroke-width:2px,stroke-dasharray: 2
    style e4 stroke-width:2px,stroke-dasharray: 2

完整示例

CPP
unsigned int VAO, VBO, EBO;

struct VertexInfo {
    glm::vec3 Position; // 顶点位置
    glm::vec3 Normal; // 法线
    glm::vec2 TexCoord; // 纹理坐标
}

// @param vbi 顶点信息数据
// @param ebi 索引数据
Mesh(const std::vector<VertexInfo> &vbi, const std::vector<unsigned int> &ebi) {
    // 计算顶点信息数据大小
    const auto vbi_size = vbi.size() * sizeof(VertexInfo);
    // 计算索引数据大小
    const auto indices_size = ebi.size() * sizeof(unsigned int);
    
    /// 生成VAO
    glGenVertexArrays(1, &VAO);
    // 绑定VAO
    glBindVertexArray(VAO);
    
    // 处理顶点信息数据
    /// 生成VBO
    glGenBuffers(1, &VBO);
    // 绑定VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    /// 传入VBO数据
    glBufferData(GL_ARRAY_BUFFER, vbi_size, vbi.data(), GL_STATIC_DRAW);
    /// 设置锚定点
    //// 位置 Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexInfo), reinterpret_cast<void *>(offsetof(VertexInfo, Position)));
    glEnableVertexAttribArray(0);
    //// 法线 Normal
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexInfo), reinterpret_cast<void *>(offsetof(VertexInfo, Normal)));
    glEnableVertexAttribArray(1);
    //// 纹理坐标 TexCoord
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexInfo), reinterpret_cast<void *>(offsetof(VertexInfo, TexCoord)));
    glEnableVertexAttribArray(2);
    // 处理顶点信息数据结束
    
    // 处理索引数据
    /// 生成EBO
    glGenBuffers(1, &EBO);
    // 绑定EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    /// 传入EBO数据
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_size * sizeof(unsigned int), ebi.data(), GL_STATIC_DRAW);
    
    // 解绑VAO
    glBindVertexArray(0);
}

~Mesh() override {
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
}
点击展开查看更多

缓冲区对象 (Buffer Object)

我们可以通过缓冲区对象将一大批数据一次性地发送到GPU上,从CPU把数据发送到GPU相对较,所以只要可能,我们都要尝试尽量一次性发送尽可能多的数据。

glGenBuffers

用于生成指定数量的缓冲区对象

C
void glGenBuffers(GLsizei n, GLuint *buffers)
点击展开查看更多
  • 参数
    • n —— 要生成的VBO数量
    • buffers —— 用于存储VBO ID的变量的指针,生成多个VBO时需要传入数组指针
  • 无返回值

glBindBuffer

将指定的缓冲区对象绑定到当前上下文中的某个目标(Target)

C
void glBindBuffer(GLenum target, GLuint buffer)
点击展开查看更多
  • 参数
    • target —— 指定缓冲区的绑定目标,将决定缓冲区的用途 ^aa4639
      • GL_ARRAY_BUFFER —— 即VBO,存储顶点属性数据(如顶点坐标、法线、颜色等)
      • GL_ELEMENT_ARRAY_BUFFER —— 即EBO,存储顶点索引数据
      • GL_UNIFORM_BUFFER —— 即UBO,存储Uniform块数据
      • ...
    • buffer —— 缓冲区对象。如果为 0,则解绑指定的目标。
  • 无返回值

glBufferData / glNamedBufferData

为缓冲区对象创建一个新的数据存储,原有的数据存储会被删除

C
void glBufferData(
	GLenum target,
	GLsizeiptr size,
	const void *data,
	GLenum usage,
)
void glNamedBufferData(
	GLuint buffer,
	GLsizeiptr size,
	const void *data,
	GLenum usage,
)
点击展开查看更多
  • 参数
    • target / buffer —— 缓冲区目标(^aa4639) / 缓冲区对象
    • size —— 要存储数据的大小(单位:字节)
    • data —— 一个指向数据的指针,该数据将被复制到数据存储中,数据的内存空间要连续
    • usage —— 希望GPU如何管理给定的数据
      • GL_STATIC_DRAW —— 数据不会或几乎不会改变
      • GL_DYNAMIC_DRAW —— 数据会经常改变
      • GL_STREAM_DRAW —— 数据每次绘制时都会改变
  • 无返回值

glDeleteBuffers

用于删除缓冲区对象,并释放资源注意:如果当前绑定的缓冲区对象被删除,则对应目标会自动解绑,绑定状态恢复为0

C
void glDeleteBuffers(GLsizei n, const GLuint * buffers)
点击展开查看更多

参数参考glGenBuffers


顶点数组对象 VAO(Vertex Array Object)

VAO是一个用于管理顶点属性配置的对象,它并不直接存储顶点数据(如坐标、颜色、纹理等),而是存储如何从缓冲对象中解析顶点数据的配置

glGenVertexArrays

用于生成指定数量的VAO

C
void glGenVertexArrays(GLsizei n, GLuint *arrays)
点击展开查看更多
  • 参数
    • n —— 要生成的VAO数量
    • buffers —— 用于存储VAO ID的变量的指针,生成多个VAO时需要传入数组指针
  • 无返回值

glBindVertexArray

用于绑定并使用VAO

C
void glBindVertexArray(GLuint array);
点击展开查看更多
  • 参数
    • array —— VAO ID
  • 无返回值

glVertexAttribPointer

定义一个顶点属性点(锚定点)

C
void glVertexAttribPointer(
	GLuint index,
 	GLint size,
 	GLenum type,
 	GLboolean normalized,
 	GLsizei stride,
 	const void * pointer,
);
点击展开查看更多
  • 参数
    • index —— 顶点属性索引,与顶点着色器in变量的location值对应
    • size —— 一个顶点属性有几个值,如vec3size3,以此类推
    • type —— 顶点属性中的值的数据类型,常见的有GL_FLOATGL_INT
    • normalized —— 是否要将传入的数据标准化
    • stride —— 传入的数据中,每个顶点属性之间的字节偏移量
    • pointer —— 数据中第一个元素的指针
  • 无返回值
    glVertexAttribPointer参数示意图

glEnableVertexAttribArray / glDisableVertexAttribArray

启用/禁用顶点属性所有顶点属性默认禁用;当不再需要某个顶点属性时,最好禁用以优化性能

C
void glEnableVertexArrayAttrib([GLuint vaobj], GLuint index);
void glDisableVertexArrayAttrib([GLuint vaobj], GLuint index);
点击展开查看更多
  • 参数
    • vaobj —— (可省略)VAO ID,若不填写该参数请先使用glBindVertexArray绑定VAO
    • index —— 顶点属性索引,与顶点着色器in变量的location值对应
  • 无返回值

glDeleteVertexArrays

用于删除VAO,并释放资源注意:如果当前绑定的VAO被删除,则会自动解绑,绑定状态恢复为0

C
void glDeleteVertexArrays(GLsizei n, const GLuint *arrays);
点击展开查看更多

参数参考glGenVertexArrays

版权声明

作者: Cheyne Xie

链接: https://chaim.eu.org/posts/244bb1fe/

许可证: CC BY-NC-SA 4.0

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Please attribute the source, use non-commercially, and maintain the same license.

开始搜索

输入关键词搜索文章内容

↑↓
ESC
⌘K 快捷键