OpenGl中的VAO、VBO与EBO

news2024/11/17 5:36:01

文章目录

  • VBO(顶点缓冲区对象)
    • VBO的使用
  • EBO(索引缓冲对象)
    • EBO的使用
  • VAO(顶点数组对象)
    • VAO的使用
  • 三者的区别
  • someting。。。

哎,很离谱,上个月学learnopengl学到一半跑去看庄懂老师的视频,结果该还的东西迟早得还,再打开之前的工程有些东西已经记不清楚了,特别是VAO、VBO与EBO这三个东西,之前就总是分不清,这里再做个笔记,以后要是忘了就再回来翻翻好了。

VBO(顶点缓冲区对象)

VAO(Vertex Buffer Object),为顶点缓冲区对象,是显卡存储空间里的一块缓存区(Buffer),用于存储 顶点坐标 / 顶点uv / 顶点法线 / 顶点颜色等数据信息。

  • 在 OpenGL 开发中,用于绘制的顶点数据首先是存储在 CPU 内存中的。
  • 而在调用 glDrawArrays 或者 glDrawElements 等接口进行绘制时,OpenGL 需要将顶点数组数据从 CPU 内存拷贝到 GPU 显存。
  • 所以如果我们的程序里需要多次绘制,那就会触发多次内存拷贝从而带来一些性能消耗。

那怎么解决?

  • 如果我们可以在 GPU 显存中缓存这些顶点数据,就可以大幅减少 CPU 内存到 GPU 显存的数据拷贝的开销,这就是 VBO 和 EBO 出现的原因。
  • VBO 和 EBO 的作用是在 GPU 显存中开辟一块存储空间来缓存顶点数据或者图元索引数据,避免每次绘制时 CPU 内存到 GPU 显存的数据拷贝,从而提升渲染性能。

VBO的使用

// 顶点数据:
GLfloat vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
};

// 使用 VBO:
GLuint VBO;
glGenBuffers(1, &VBO); // 创建 VBO 对象
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 把新创建的 VBO 绑定到 GL_ARRAY_BUFFER 目标上,同时也绑定到了 OpenGL 渲染管线上
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据 (CPU 内存) 拷贝到 VBO(GPU 显存)

// 绘制:
glDrawArrays(GL_TRIANGLES, 0, 3); // 使用 glDrawArrays 来绘制

整个过程还是比较浅显易懂的:做了一次 CPU 到 GPU 的数据拷贝。


EBO(索引缓冲对象)

EBO(Element Buffer Object),和顶点缓冲对象一样,EBO也是一个缓冲,它专门储存索引,OpenGL调用这些顶点的索引来决定该绘制哪个顶点。

EBO的使用

// 这次我们只定义了 4 个顶点:
GLfloat vertices[] = {
     0.5f,  0.5f, 0.0f, // 右上角
     0.5f, -0.5f, 0.0f, // 右下角
    -0.5f, -0.5f, 0.0f, // 左下角
    -0.5f,  0.5f, 0.0f  // 左上角
};

// 但是通过索引指定了每个三角形的 3 个顶点:
GLuint indices[] = { // 注意索引从 0 开始! 
    0, 1, 3, // 第一个三角形
    1, 2, 3  // 第二个三角形
};

// 使用 VBO:
GLuint VBO;
glGenBuffers(1, &VBO); // 创建 VBO 对象
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 把新创建的 VBO 绑定到 GL_ARRAY_BUFFER 目标上,同时也绑定到了 OpenGL 渲染管线上
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据 (CPU 内存) 拷贝到 VBO(GPU 显存)

// 使用 EBO:
GLuint EBO;
glGenBuffers(1, &EBO); // 创建 EBO 对象
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // 把新创建的 EBO 绑定到 GL_ELEMENT_ARRAY_BUFFER 目标上,同时也绑定到了 OpenGL 渲染管线上
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 将所有顶点数据 (CPU 内存) 拷贝到 EBO(GPU 显存),并设定按照indices顺序来渲染

// 绘制:glDrawElements替换掉glDrawArrays函数,表示我们要从索引缓冲区渲染三角形
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 使用 glDrawElements 来绘制
  • glDrawElements函数从当前绑定到GL_ELEMENT_ARRAY_BUFFER目标的EBO中获取其索引。
  • 整个过程比 VBO 略复杂了一点,但是还是很好理解的:去掉重复顶点,通过索引指定绘制顶点,创建 VBO 做一次顶点数据拷贝,创建 EBO 做了一次索引数据拷贝。

VAO(顶点数组对象)

VAO(Vertex Array Object),VAO是所有顶点数据的状态集合。它存储了顶点数据的格式以及顶点数据所需的缓存对象的引用,任何随后的顶性调用都会储存在这个VAO中。

  • 通过对 VBO、EBO 的使用,我们可以减少 CPU 到 GPU 内存拷贝来提高性能。
  • 但是如果我们需要绘制大量的顶点和物体时,每次绘制都需要绑定正确的缓冲对象并为每个物体配置所有顶点属性,这样一大堆操作很是麻烦。
  • 是否可以用一种对象来储存这些状态配置,使得我们需要的时候直接绑定这个对象就可以切换到正确的状态呢?这就是 VAO 要解决的问题。
  • 如果说 VBO、EBO 是通过 GPU 显存的缓存来减少内存拷贝从而提升性能,那么 VAO 则略有不同:VAO 的主要作用是用于管理 VBO 或 EBO,减少 glBindBuffer、glEnableVertexAttribArray、glVertexAttribPointer 这些调用操作,高效地实现在顶点数组配置之间切换。

VAO的使用

// 顶点数据:
GLfloat vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
};

// 创建 VBO:
GLuint VBO;
glGenBuffers(1, &VBO); // 创建 VBO 对象

// 创建 VAO:
GLuint VAO;
glGenVertexArrays(1, &VAO); // 创建 VAO 对象,注意这里用的是 glGenVertexArrays

// 在绑定 VAO 后操作 VBO,当前 VAO 会记录 VBO 的操作,我们下面用缩进表示操作 VBO 的代码:
glBindVertexArray(VAO); // 绑定 VAO,注意这里用的是 glBindVertexArray
    // 绑定 VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    // 把顶点数组复制到缓冲中供 OpenGL 使用
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 
    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *) 0);
    glEnableVertexAttribArray(0);
// 解绑 VAO
glBindVertexArray(0);

// ...省略其他代码...

// 会被调用多次的绘制代码:
glBindVertexArray(VAO); // 绑定使用 VAO 绘制
glDrawArrays(GL_TRIANGLES, 0, 3); // 使用 glDrawArrays 来绘制
glBindVertexArray(0); // 解绑 VAO

上面的代码相比我们用 VBO 绘制三角形的代码还是复杂一些的,上面的代码可以理解为:使用 VAO 记录 VBO 的操作相当于创建了一个快捷方式,后面直接用 VAO 快捷方式绘制。


三者的区别

  • VAO中存储着VBO的信息和EBO的信息。
  • VBO和EBO存储的都是顶点的信息。
  • 一个VAO对应一个物体
  • 一个VBO对应一个物品的所有属性(顶点坐标、颜色等,除顶点索引外)。
  • 一个EBO仅对应一个物品的一种属性(顶点索引属性)。

在这里插入图片描述

someting。。。

参考来自:

  • 这个
  • 这个
  • 还有这个

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/797859.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NineData支持最受欢迎数据库PostgreSQL

根据在 Stack Overflow 发布的 2023 开发者调研报告中显示,PostgreSQL 以 45% vs 41% 的受欢迎比率战胜 MySQL,成为新的最受欢迎的数据库。NineData 也在近期支持了 PostgreSQL,用户可以在 NineData 平台上进行创建数据库/Schema、管理用户与…

BTTES,2101505-88-6,是各种化学生物实验中生物偶联的理想选择

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ 规格单位:g |货期:按照具体的库存进行提供 | 纯度:95% PART1----​试剂描述: BTTES是铜(I)催化的叠氮化物-炔烃环加成(CuAAC&#x…

整数替换(力扣)HashMap + 递归 JAVA

给定一个正整数 n ,你可以做如下操作: 如果 n 是偶数,则用 n / 2替换 n 。 如果 n 是奇数,则可以用 n 1或n - 1替换 n 。 返回 n 变为 1 所需的 最小替换次数 。 示例 1: 输入:n 8 输出:3 解释…

系统架构设计师-软件架构设计(4)

目录 一、软件架构评估 1、敏感点 2、权衡点 3、风险点 4、非风险点 5、架构评估方法 5.1 基于调查问卷或检查表的方式 5.2 基于度量的方式 5.3 基于场景的方式 6、基于场景的评估方法 6.1 软件架构分析法(SAAM) 6.2 架构权衡分析法(ATAM&am…

vue 封装一个鼠标拖动选择时间段功能

<template><div class"timeRange"><div class"calendar"><table><thead><tr><th rowspan"6" class"weekRow"><b>周/时间</b></th><th colspan"24"><…

docker容器引擎(三)

docker 一、Docker 的数据管理1&#xff0e;数据卷2&#xff0e;数据卷容器 二、容器互联&#xff08;使用centos镜像&#xff09;三、docker镜像的创建创建镜像的方法DockerfileDocker 镜像结构的分层Dockerfile 操作常用的指令&#xff1a; 四、Dockerfile 案例 一、Docker 的…

Java从入门到精通(一)

Java从入门到精通&#xff08;一&#xff09; 前言 温故而知新&#xff0c;闲着没事干&#xff0c;准备将Java编程语言的知识点从头梳理一遍&#xff0c;整理成笔记&#xff0c;逐篇发布。 部分图片素材来源与B站“黑马程序员”的课程。 一 Java背景 Java是1995年 由Sun公司…

error CS0246: 未能找到类型或命名空间名“Newtonsoft”(是否缺少 using 指令或程序集引用?)

error CS0246: 未能找到类型或命名空间名“Newtonsoft”(是否缺少 using 指令或程序集引用?) 如图&#xff0c;明明已经引用了命名空间&#xff0c;可以点击生成报错。找了很长时间的原因&#xff0c;最后终于解决了问题。 原因是Newtonsoft这个dll文件只支持.net 4.5框架&…

互联网搜索的学习笔记

1. 参考资料 《Internet Search Tips》《Google Search Operators: The Complete List (42 Advanced Operators)》 2. 预备知识 2.1 查询语法 2.1.1 -&#xff1a;排除符 用于排除指定关键字。例如&#xff0c;如果想搜索“苹果”但不想看到“苹果手机”的结果&#xff0c;…

【Spring】IOC的原理

一、 IOC 的概念 Spring 的 IOC &#xff0c;即控制反转&#xff0c;所谓控制反转 —— 本来管理业务对象&#xff08;bean&#xff09;的操作是由我们程序员去做的&#xff0c;但是有了 Spring 核心容器后&#xff0c;这些 Bean 对象的创建和管理交给我们Spring容器去做了&am…

疫苗生产精细困难,有了物联网网关,让生产 更轻松

疫苗生产背景 生产出现的问题 项目工期十分紧张 无法及时获知产线生产进度&#xff0c;不易进行计划调整 无法准确的安排现场生产计划 产品线数量多&#xff0c;纸质记录及流程近10万页 设备采集数量庞大&#xff0c;超过40000点 设备管理不明确、报修维修等无法及时通知…

QPoint、QLine、QSize、QRect

QPoint、QLine、QSize、QRect QPointQLineQSizeQRect QPoint // 构造函数 // 构造一个坐标原点, 即(0, 0) QPoint::QPoint(); // 参数为 x轴坐标, y轴坐标 QPoint::QPoint(int xpos, int ypos);// 设置x轴坐标 void QPoint::setX(int x); // 设置y轴坐标 void QPoint::setY(in…

Linux操作系统~必考面试题⑦

1、vim 命令 Vim是从 vi 发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富&#xff0c;在程序员中被广泛使用。 打开文件并跳到第 10 行&#xff1a; vim 10 filename.txt 打开文件跳到第一个匹配的行&#xff1a; vim /search-term filenam…

基于传统网络架构训练图像分类模型(上传到colab中进行运算)

一 部署colab环境 部署colab参考网站 相关文件&#xff1a;提取码&#xff1a;o2gn 在google drive中部署以上涉及的相关文件夹 二 对这个项目的解释 这个项目主要是对5类花的图像进行分类 采用迁移学习的方法&#xff0c;迁移学习resnet网络&#xff0c;利用原来的权重作…

stm32f103VET6和stm32f103c8t6有什么区别?

我来终结下这个问题。 这两款单片机我都用过&#xff0c;其中无际单片机特训营其中一款wifi报警主机项目就是用了stm32f103c8t6。 stm32f103VET6和stm32f103c8t6都是STMicroelectronics公司推出基于ARM Cortex-M3内核的单片机。 它们在硬件规格和性能上存在一些差异&#xff…

SpringSecurity认证授权具体流程步骤(具体实例)

本案例是通过使用SpringSecurity来实现通过读取数据库中的数据&#xff0c;来完成认证授权的案例。 1. 向数据库中添加具体实例 创建出五个表&#xff0c;五个表之间的关系为&#xff1a; sys_user&#xff1a;登录表&#xff0c;用于登陆后查询id sys_user_role&#xff1a;…

Flink集群运行模式--Standalone运行模式

Flink集群运行模式--Standalone运行模式 一、实验目的二、实验内容三、实验原理四、实验环境五、实验步骤5.1 部署模式5.1.1 会话模式&#xff08;Session Mode&#xff09;5.1.2 单作业模式&#xff08;Per-Job Mode&#xff09;5.1.3 应用模式&#xff08;Application Mode&a…

三层交换机实现DHCP功能

典型操作&#xff1a;三层交换机VLAN实现网络 可以实现基本的企业需求 华为的三层交换机实现DHCP功能&#xff0c;需要给vlan划分地址池 1.网络拓扑图 2.三层交换机的配置 //三层交换机的配置 //配置IP地址池&#xff0c;实现DHCP时分配给vlan下的终端 [Huawei]ip pool vl…

玩转smardaten | 零基础构建多维数据可视化大屏(最全攻略)

不要再问睿睿&#xff1a;数据可视化大屏怎么做啦&#xff01; 没学过任何编程代码怎么办&#xff0c;能做吗&#xff1f;根本不是问题&#xff01; 这篇文章手把手教你&#xff0c;全方位攻略smardaten数据可视化大屏&#xff08;搭建无需代码&#xff09;~~ 一、可视化大屏…

TSINGSEE青犀视频汇聚融合平台EasyCVR的中性化版本如何配置?

TSINGSEE青犀视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等&#xff0c;平台融合性强、开放度高、部署轻快&#xff0c;在智慧工地、智慧园区…