当前位置: 首页 > news >正文

【OpenGL】Triangle、VBO、VAO

GPU有成千上万的小核心,每个核心都可以跑专门的小程序,这种程序称为shader。

GPU有固定的shader流水线,我们也可以通过自定义重写shader,精细的控制流水线的每一部分。

蓝色区域是我们可以重写的shader

image

VBO:顶点数据仓库

  • 功能
    VBO是显存中的二进制数据块,负责高效存储顶点数据(如坐标、颜色、法线等),大幅减少CPU-GPU通信开销。
  • 特点
    • 纯数据容器:以连续二进制流存储,例如 [x1,y1,z1,r1,g1,b1,x2,y2,z2,...]
    • 灵活使用模式:支持静态(GL_STATIC_DRAW)、动态(GL_DYNAMIC_DRAW)等存储策略。

image

1. 生成缓冲对象

使用 glGenBuffer 函数创建一个新的 VBO,并返回其 ID。

GLuint vbo;
glGenBuffers(1, &vbo); // 1 表示一次性创建几个,后一个参数提供数组指针,将ID回存入数组

2. 绑定缓冲对象

使用 glBindBuffer 函数将创建的 VBO 绑定为当前的顶点缓冲对象。

OPenGL状态机配置阶段只支持激活一个VBO,所以后续数据传入也必须指定这个缓冲区类型。

glBindBuffer(GL_ARRAY_BUFFER, vbo);

3. 上传数据

使用 glBufferData 函数将顶点数据上传到显卡内存。

float vertices[] = {// 顶点数据,例如三角形的三个顶点0.0f,  1.0f, 0.0f,-1.0f, -1.0f, 0.0f,1.0f, -1.0f, 0.0f
};//GL_STATIC_DRAW 表示数据不会频繁更改。
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

传入到之前绑定好类型和对象的缓冲区

数据传到的缓冲区类型要和绑定的一致

// 绑定 VBO_A 并传输数据
glBindBuffer(GL_ARRAY_BUFFER, vboA);
glBufferData(GL_ARRAY_BUFFER, sizeof(dataA), dataA, GL_STATIC_DRAW); // 数据传至 vboA// 绑定 VBO_B 并传输数据
glBindBuffer(GL_ARRAY_BUFFER, vboB);
glBufferData(GL_ARRAY_BUFFER, sizeof(dataB), dataB, GL_STATIC_DRAW); // 数据传至 vboB

VAO:数据解析蓝图

  • 功能
    VAO定义VBO中数据的解析规则,通过顶点属性指定数据结构、类型和用途,实现数据与着色器的对接。
  • 核心配置
    • 属性指针glVertexAttribPointer):定义数据起始偏移、类型(如GL_FLOAT)、向量维度(如3D坐标)等。
    • 属性启用glEnableVertexAttribArray):激活对应属性通道,与着色器layout(location = N)绑定。
  • 优势
    • 状态封装:绘制时只需绑定VAO,自动恢复所有属性配置。
    • 多VBO支持:可关联多个VBO(如坐标VBO、颜色VBO),通过不同属性指针区分。

其同一存储在显存中

1. 生成 VAO
使用 glGenVertexArrays 函数创建一个新的 VAO,并返回其 ID。

GLuint VAO;
glGenVertexArrays(1, &VAO);

2. 绑定 VAO

使用 glBindVertexArray 函数将创建的 VAO 绑定为当前的顶点数组对象。绑定 VAO 后,所有后续的顶点属性配置(如 VBO 绑定、顶点属性指针设置)都会存储在这个 VAO 中。

glBindVertexArray(VAO);

后续 glVertexAttribPointerglEnableVertexAttribArray、VBO的绑定状态,会自动存入 VAO

3. 生成并绑定VBO

GLfloat vertices[] = {// 顶点坐标-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f,  0.5f, 0.0f
};GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

4. 设置顶点属性解析方式

// 设置顶点属性解析方式
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0); // 启用顶点解析

glVertexAttribPointer 时,VAO会将当前绑定的VBO的引用和配置记录下,可以记录无限个绑定的。渲染时批量取出

graph TBA[初始化阶段] --> B[创建 VAO 并绑定]B --> C1[绑定 vbo_position]C1 --> D1[配置属性0 位置]B --> C2[绑定 vbo_color]C2 --> D2[配置属性1 颜色]A --> E[解绑 VAO 和 VBO]F[渲染阶段] --> G[绑定 VAO]G --> H[自动恢复属性0→vbo_position]G --> I[自动恢复属性1→vbo_color]G --> J[调用 glDrawArrays]

image

完整流程示例

#include <iostream>
#include <cstdlib>#include <GL/glew.h>
#include <GLFW/glfw3.h>// shader硬编码可以定义一个宏 #define GET_STR(x) #x 会自动加双引号和换行
#define GET_STR(x) #xfloat vertices[] = {-0.5f, -0.5f, 0.0f, // 左下角0.5f, -0.5f, 0.0f, // 右下角0.0f,  0.5f, 0.0f  // 顶部
};const char *vertexShaderSource = R"(#version 330 corelayout (location = 0) in vec3 aPos;void main(){gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);}
)";const char *fragmentShaderSource = R"(#version 330 coreout vec4 FragColor;void main(){FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); // 绘制一个橙色三角形}
)";void processInput(GLFWwindow *window) {// 检查ESC键状态if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {glfwSetWindowShouldClose(window, true); // 退出程序}
}int main(int, char**) {// 初始化GLFWif (!glfwInit()) {std::cerr << "Failed to initialize GLFW" << std::endl;return EXIT_FAILURE;}// 设置OpenGL版本和配置文件glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用核心配置glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);// 创建窗口GLFWwindow* window = glfwCreateWindow(800, 600, "My OpenGL Game", NULL, NULL);if (window == NULL) {std::cerr << "Failed to create GLFW window" << std::endl;glfwTerminate(); // 退出return -1;}// 设置当前上下文glfwMakeContextCurrent(window); // 将这个窗口作为当前glfw上下文// 初始化GLEWglewExperimental = GL_TRUE;  // 需要在glewInit()之前设置if (glewInit() != GLEW_OK) {std::cerr << "Failed to initialize GLEW" << std::endl;glfwTerminate();return EXIT_FAILURE;}// 设置视口,左下角起始坐标点,可以绘制的宽高glViewport(0, 0, 800, 600);// VAOunsigned int VAO;glGenVertexArrays(1, &VAO);glBindVertexArray(VAO);// VBOunsigned int VBO;glGenBuffers(1, &VBO);glBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定VBOglBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// set vertex attribute pointersglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// vertex shaderunsigned int vertexShader;vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // count: 几个字串glCompileShader(vertexShader);// fragment shaderunsigned int fragmentShader;fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// shader programunsigned int shaderProgram;shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// 主渲染循环// 当前输入作用于当前帧while (!glfwWindowShouldClose(window)) {glfwPollEvents(); // 获取键盘和鼠标事件传递到window上下文processInput(window); // 判断上下文中的事件// 设置背景色glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置清空缓冲区后填充的颜色,默认值,背景色glClear(GL_COLOR_BUFFER_BIT); // 清空缓冲区颜色glBindVertexArray(VAO);glUseProgram(shaderProgram);glDrawArrays(GL_TRIANGLES, 0, 3);// 交换缓冲区glfwSwapBuffers(window); // 双缓冲区,一个用于显示,一个用于绘制}glfwTerminate();return 0;
}
http://www.njgz.com.cn/news/248.html

相关文章:

  • ,
  • 更新日志
  • 板子
  • 2025.07.26 学习
  • SumatraPDF-pdf阅读器
  • 数据仓库、数据湖、湖仓一体,别再傻傻分不清了 - 智慧园区
  • xx
  • 2025 暑假多校(更新中)
  • llm-universe
  • 2025.7.27
  • 切比雪夫距离和曼哈顿距离
  • Godot中用C#脚本自定义信号
  • zookper笔记
  • ABC 416 F
  • 除法取模需使用费马小定理或者欧拉函数
  • LLaMA Factory:一站式大模型微调框架的技术介绍
  • 2025727
  • 读《大道至简》有感
  • Datawhale AI夏令营-DeepSeek数学推理蒸馏:轻量化模型的高效推理优化
  • Windows操作QEMU安装ARM架构的操作系统
  • 34th@202508工作清单@20250726
  • 用 Go 与 Tesseract 构建验证码识别 HTTP 服务
  • CS144 Lab2: TCPReceiver实现全解析
  • windows操作QEMU安装ARM架构操作系统
  • 使用 Go 构建基于 Tesseract 的命令行验证码识别工具
  • SpringCloud微服务架构-Gateway服务网关
  • 暑期生活学习笔记
  • 好的调试
  • 20250726 之所思 - 人生如梦
  • Day15 面向对象编程