【OpenGL】VAO (顶点缓冲对象)、VBO(顶点数组对象) 与 EBO (索引缓冲对象)使用示例

VAO、VBO 与 EBO 详解及现代 OpenGL 使用指南

#运行截图
在这里插入图片描述

🧩 核心概念解析
对象作用优势绑定目标
VBO (顶点缓冲对象)存储顶点数据(位置、颜色、法线等)减少CPU→GPU数据传输GL_ARRAY_BUFFER
VAO (顶点数组对象)封装VBO配置和属性指针一键切换顶点配置状态-
EBO (索引缓冲对象)存储顶点索引实现顶点复用,减少重复数据GL_ELEMENT_ARRAY_BUFFER
🔄 数据流示意图
CPU数据 → VBO (显存) → VAO (属性映射) → 顶点着色器
              ↑
EBO (索引) ────┘

🚀 完整使用示例(OpenGL 3.3+核心模式)

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

const char* vertexShaderSrc = R"(
    #version 330 core
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 aColor;
    out vec3 color;
    void main() {
        gl_Position = vec4(aPos, 1.0);
        color = aColor;
    }
)";

const char* fragmentShaderSrc = R"(
    #version 330 core
    in vec3 color;
    out vec4 FragColor;
    void main() {
        FragColor = vec4(color, 1.0);
    }
)";

int main() {
    // 初始化GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // 创建窗口
    GLFWwindow* window = glfwCreateWindow(800, 600, "VAO/VBO/EBO Demo", NULL, NULL);
    glfwMakeContextCurrent(window);
    gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);

    // 编译着色器
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL);
    glCompileShader(vertexShader);
    
    // [添加错误检查...]

    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSrc, NULL);
    glCompileShader(fragmentShader);
    
    unsigned int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // 顶点数据:位置(3) + 颜色(3)
    float vertices[] = {
        // 位置          // 颜色
        -0.5f, 0.5f, 0.0f,  1.0f, 0.0f, 0.0f,  // 左上
         0.5f, 0.5f, 0.0f,   0.0f, 1.0f, 0.0f,  // 右上
         0.5f, -0.5f, 0.0f,  0.0f, 0.0f, 1.0f,  // 右下
        -0.5f, -0.5f, 0.0f,  1.0f, 1.0f, 0.0f   // 左下
    };

    // 索引数据(逆时针缠绕顺序)
    unsigned int indices[] = {
        0, 1, 2,  // 右上三角形
        0, 2, 3   // 左下三角形
    };

    // 1. 创建并绑定VAO(状态记录开始)
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    // 2. 创建并配置VBO
    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 3. 创建并配置EBO
    unsigned int EBO;
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // 4. 设置顶点属性指针
    // 位置属性 (location = 0)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    // 颜色属性 (location = 1)
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // 5. 解绑VAO(保留EBO绑定)
    glBindVertexArray(0); 

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {
        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);  // 一键激活所有配置
        
        // 使用索引绘制矩形
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 资源清理
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(shaderProgram);

    glfwTerminate();
    return 0;
}

🔑 关键操作解析

  1. VAO 状态管理

    glGenVertexArrays(1, &VAO);        // 创建VAO
    glBindVertexArray(VAO);             // 激活状态记录
    // ...配置VBO和属性指针...
    glBindVertexArray(0);               // 停止记录
    
  2. VBO 数据传输

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定到目标
    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, usage); // 传输数据
    
  3. EBO 索引配置

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // 注意:此绑定会被VAO记录
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
  4. 属性指针设置

    // 参数:属性位置, 元素数量, 类型, 是否标准化, 步长, 偏移量
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);  // 启用属性通道
    
  5. 索引绘制

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    

💡 最佳实践建议

  1. 初始化阶段

    • 创建所有VAO/VBO/EBO
    • 一次性配置顶点属性
    • 解绑VAO(保留配置)
  2. 渲染循环

    glUseProgram(shader);
    glBindVertexArray(VAO);        // 激活物体顶点配置
    glDrawElements(...);           // 绘制
    // 无需解绑VAO(效率考虑)
    
  3. 资源管理

    • VAO销毁时自动解除关联的EBO绑定
    • VBO需手动销毁(可被多个VAO共享)
    • 避免在循环中创建/销毁缓冲对象
  4. 高级用法

    // 实例化渲染
    glDrawElementsInstanced(...);
    
    // 动态VBO更新
    glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
    

性能提示:使用EBO可减少约50%顶点数据传输(矩形案例:6顶点→4顶点+6索引)。复杂模型优化效果更显著!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晴雨日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值